video_filter: motionblur: use C99 loop declaration
[vlc.git] / src / audio_output / dec.c
blobcafaba675ea2a5cab109231d6b3b513a7d2decce
1 /*****************************************************************************
2 * dec.c : audio output API towards decoders
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
5 * $Id$
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 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <assert.h>
33 #include <vlc_common.h>
34 #include <vlc_aout.h>
35 #include <vlc_input.h>
37 #include "aout_internal.h"
38 #include "libvlc.h"
40 /**
41 * Creates an audio output
43 int aout_DecNew( audio_output_t *p_aout,
44 const audio_sample_format_t *p_format,
45 const audio_replay_gain_t *p_replay_gain,
46 const aout_request_vout_t *p_request_vout )
48 /* Sanitize audio format */
49 if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
51 msg_Err( p_aout, "incompatible audio channels count with layout mask" );
52 return -1;
55 if( p_format->i_rate > 352800 )
57 msg_Err( p_aout, "excessive audio sample frequency (%u)",
58 p_format->i_rate );
59 return -1;
61 if( p_format->i_rate < 4000 )
63 msg_Err( p_aout, "too low audio sample frequency (%u)",
64 p_format->i_rate );
65 return -1;
68 var_Create (p_aout, "stereo-mode",
69 VLC_VAR_INTEGER | VLC_VAR_HASCHOICE | VLC_VAR_DOINHERIT);
70 vlc_value_t txt;
71 txt.psz_string = _("Stereo audio mode");
72 var_Change (p_aout, "stereo-mode", VLC_VAR_SETTEXT, &txt, NULL);
74 aout_owner_t *owner = aout_owner(p_aout);
76 /* TODO: reduce lock scope depending on decoder's real need */
77 aout_OutputLock (p_aout);
79 /* Create the audio output stream */
80 owner->volume = aout_volume_New (p_aout, p_replay_gain);
82 atomic_store (&owner->restart, 0);
83 owner->input_format = *p_format;
84 owner->mixer_format = owner->input_format;
85 owner->request_vout = *p_request_vout;
87 if (aout_OutputNew (p_aout, &owner->mixer_format))
88 goto error;
89 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
91 /* Create the audio filtering "input" pipeline */
92 owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
93 &owner->request_vout);
94 if (owner->filters == NULL)
96 aout_OutputDelete (p_aout);
97 error:
98 aout_volume_Delete (owner->volume);
99 aout_OutputUnlock (p_aout);
100 var_Destroy (p_aout, "stereo-mode");
101 return -1;
104 owner->sync.end = VLC_TS_INVALID;
105 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
106 owner->sync.discontinuity = true;
107 aout_OutputUnlock (p_aout);
109 atomic_init (&owner->buffers_lost, 0);
110 return 0;
114 * Stops all plugins involved in the audio output.
116 void aout_DecDelete (audio_output_t *aout)
118 aout_owner_t *owner = aout_owner (aout);
120 aout_OutputLock (aout);
121 if (owner->mixer_format.i_format)
123 aout_FiltersDelete (aout, owner->filters);
124 aout_OutputDelete (aout);
126 aout_volume_Delete (owner->volume);
127 aout_OutputUnlock (aout);
128 var_Destroy (aout, "stereo-mode");
131 static int aout_CheckReady (audio_output_t *aout)
133 aout_owner_t *owner = aout_owner (aout);
135 int restart = atomic_exchange (&owner->restart, 0);
136 if (unlikely(restart))
138 if (owner->mixer_format.i_format)
139 aout_FiltersDelete (aout, owner->filters);
141 if (restart & AOUT_RESTART_OUTPUT)
142 { /* Reinitializes the output */
143 msg_Dbg (aout, "restarting output...");
144 if (owner->mixer_format.i_format)
145 aout_OutputDelete (aout);
146 owner->mixer_format = owner->input_format;
147 if (aout_OutputNew (aout, &owner->mixer_format))
148 owner->mixer_format.i_format = 0;
149 aout_volume_SetFormat (owner->volume,
150 owner->mixer_format.i_format);
153 msg_Dbg (aout, "restarting filters...");
154 owner->sync.end = VLC_TS_INVALID;
155 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
157 if (owner->mixer_format.i_format)
159 owner->filters = aout_FiltersNew (aout, &owner->input_format,
160 &owner->mixer_format,
161 &owner->request_vout);
162 if (owner->filters == NULL)
164 aout_OutputDelete (aout);
165 owner->mixer_format.i_format = 0;
168 /* TODO: This would be a good time to call clean up any video output
169 * left over by an audio visualization:
170 input_resource_TerminatVout(MAGIC HERE); */
172 return (owner->mixer_format.i_format) ? 0 : -1;
176 * Marks the audio output for restart, to update any parameter of the output
177 * plug-in (e.g. output device or channel mapping).
179 void aout_RequestRestart (audio_output_t *aout, unsigned mode)
181 aout_owner_t *owner = aout_owner (aout);
182 atomic_fetch_or (&owner->restart, mode);
183 msg_Dbg (aout, "restart requested (%u)", mode);
187 * Buffer management
190 static void aout_StopResampling (audio_output_t *aout)
192 aout_owner_t *owner = aout_owner (aout);
194 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
195 aout_FiltersAdjustResampling (owner->filters, 0);
198 static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts)
200 aout_owner_t *owner = aout_owner (aout);
201 const audio_sample_format_t *fmt = &owner->mixer_format;
202 size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
203 block_t *block;
205 if (AOUT_FMT_SPDIF(fmt))
206 block = block_Alloc (4 * frames);
207 else
208 block = block_Alloc (frames * fmt->i_bytes_per_frame);
209 if (unlikely(block == NULL))
210 return; /* uho! */
212 msg_Dbg (aout, "inserting %zu zeroes", frames);
213 memset (block->p_buffer, 0, block->i_buffer);
214 block->i_nb_samples = frames;
215 block->i_pts = pts;
216 block->i_dts = pts;
217 block->i_length = length;
218 aout_OutputPlay (aout, block);
221 static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
222 int input_rate)
224 aout_owner_t *owner = aout_owner (aout);
225 mtime_t drift;
228 * Depending on the drift between the actual and intended playback times,
229 * the audio core may ignore the drift, trigger upsampling or downsampling,
230 * insert silence or even discard samples.
231 * Future VLC versions may instead adjust the input rate.
233 * The audio output plugin is responsible for estimating its actual
234 * playback time, or rather the estimated time when the next sample will
235 * be played. (The actual playback time is always the current time, that is
236 * to say mdate(). It is not an useful statistic.)
238 * Most audio output plugins can estimate the delay until playback of
239 * the next sample to be written to the buffer, or equally the time until
240 * all samples in the buffer will have been played. Then:
241 * pts = mdate() + delay
243 if (aout_OutputTimeGet (aout, &drift) != 0)
244 return; /* nothing can be done if timing is unknown */
245 drift += mdate () - dec_pts;
247 /* Late audio output.
248 * This can happen due to insufficient caching, scheduling jitter
249 * or bug in the decoder. Ideally, the output would seek backward. But that
250 * is not portable, not supported by some hardware and often unsafe/buggy
251 * where supported. The other alternative is to flush the buffers
252 * completely. */
253 if (drift > (owner->sync.discontinuity ? 0
254 : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
256 if (!owner->sync.discontinuity)
257 msg_Warn (aout, "playback way too late (%"PRId64"): "
258 "flushing buffers", drift);
259 else
260 msg_Dbg (aout, "playback too late (%"PRId64"): "
261 "flushing buffers", drift);
262 aout_OutputFlush (aout, false);
264 aout_StopResampling (aout);
265 owner->sync.end = VLC_TS_INVALID;
266 owner->sync.discontinuity = true;
268 /* Now the output might be too early... Recheck. */
269 if (aout_OutputTimeGet (aout, &drift) != 0)
270 return; /* nothing can be done if timing is unknown */
271 drift += mdate () - dec_pts;
274 /* Early audio output.
275 * This is rare except at startup when the buffers are still empty. */
276 if (drift < (owner->sync.discontinuity ? 0
277 : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
279 if (!owner->sync.discontinuity)
280 msg_Warn (aout, "playback way too early (%"PRId64"): "
281 "playing silence", drift);
282 aout_DecSilence (aout, -drift, dec_pts);
284 aout_StopResampling (aout);
285 owner->sync.discontinuity = true;
286 drift = 0;
289 /* Resampling */
290 if (drift > +AOUT_MAX_PTS_DELAY
291 && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
293 msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
294 drift);
295 owner->sync.resamp_type = AOUT_RESAMPLING_UP;
296 owner->sync.resamp_start_drift = +drift;
298 if (drift < -AOUT_MAX_PTS_ADVANCE
299 && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
301 msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
302 drift);
303 owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
304 owner->sync.resamp_start_drift = -drift;
307 if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
308 return; /* Everything is fine. Nothing to do. */
310 if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
311 { /* If the drift is ever increasing, then something is seriously wrong.
312 * Cease resampling and hope for the best. */
313 msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
314 "stopping resampling", drift);
315 aout_StopResampling (aout);
316 return;
319 /* Resampling has been triggered earlier. This checks if it needs to be
320 * increased or decreased. Resampling rate changes must be kept slow for
321 * the comfort of listeners. */
322 int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
324 if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
325 /* If the drift has been reduced from more than half its initial
326 * value, then it is time to switch back the resampling direction. */
327 adj *= -1;
329 if (!aout_FiltersAdjustResampling (owner->filters, adj))
330 { /* Everything is back to normal: stop resampling. */
331 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
332 msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
336 /*****************************************************************************
337 * aout_DecPlay : filter & mix the decoded buffer
338 *****************************************************************************/
339 int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
341 aout_owner_t *owner = aout_owner (aout);
343 assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
344 assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
345 assert (block->i_pts >= VLC_TS_0);
347 block->i_length = CLOCK_FREQ * block->i_nb_samples
348 / owner->input_format.i_rate;
350 aout_OutputLock (aout);
351 if (unlikely(aout_CheckReady (aout)))
352 goto drop; /* Pipeline is unrecoverably broken :-( */
354 const mtime_t now = mdate (), advance = block->i_pts - now;
355 if (advance < -AOUT_MAX_PTS_DELAY)
356 { /* Late buffer can be caused by bugs in the decoder, by scheduling
357 * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
358 * insufficient. We assume the PTS is wrong and play the buffer anyway:
359 * Hopefully video has encountered a similar PTS problem as audio. */
360 msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
361 goto drop;
363 if (advance > AOUT_MAX_ADVANCE_TIME)
364 { /* Early buffers can only be caused by bugs in the decoder. */
365 msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
366 goto drop;
368 if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
369 owner->sync.discontinuity = true;
371 block = aout_FiltersPlay (owner->filters, block, input_rate);
372 if (block == NULL)
373 goto lost;
375 /* Software volume */
376 aout_volume_Amplify (owner->volume, block);
378 /* Drift correction */
379 aout_DecSynchronize (aout, block->i_pts, input_rate);
381 /* Output */
382 owner->sync.end = block->i_pts + block->i_length + 1;
383 owner->sync.discontinuity = false;
384 aout_OutputPlay (aout, block);
385 out:
386 aout_OutputUnlock (aout);
387 return 0;
388 drop:
389 owner->sync.discontinuity = true;
390 block_Release (block);
391 lost:
392 atomic_fetch_add(&owner->buffers_lost, 1);
393 goto out;
396 int aout_DecGetResetLost (audio_output_t *aout)
398 aout_owner_t *owner = aout_owner (aout);
399 return atomic_exchange(&owner->buffers_lost, 0);
402 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
404 aout_owner_t *owner = aout_owner (aout);
406 aout_OutputLock (aout);
407 if (owner->sync.end != VLC_TS_INVALID)
409 if (paused)
410 owner->sync.end -= date;
411 else
412 owner->sync.end += date;
414 if (owner->mixer_format.i_format)
415 aout_OutputPause (aout, paused, date);
416 aout_OutputUnlock (aout);
419 void aout_DecFlush (audio_output_t *aout, bool wait)
421 aout_owner_t *owner = aout_owner (aout);
423 aout_OutputLock (aout);
424 owner->sync.end = VLC_TS_INVALID;
425 if (owner->mixer_format.i_format)
426 aout_OutputFlush (aout, wait);
427 aout_OutputUnlock (aout);