packetizer: hxxx: fix DirectTV extraction
[vlc.git] / src / audio_output / dec.c
blobf37a6e396b6fb228a5126a2ab82d68f9c8b86d2a
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 )
49 /* Sanitize audio format, input need to have a valid physical channels
50 * layout or a valid number of channels. */
51 int i_map_channels = aout_FormatNbChannels( p_format );
52 if( ( i_map_channels == 0 && p_format->i_channels == 0 )
53 || i_map_channels > AOUT_CHAN_MAX || p_format->i_channels > INPUT_CHAN_MAX )
55 msg_Err( p_aout, "invalid audio channels count" );
56 return -1;
59 if( p_format->i_rate > 352800 )
61 msg_Err( p_aout, "excessive audio sample frequency (%u)",
62 p_format->i_rate );
63 return -1;
65 if( p_format->i_rate < 4000 )
67 msg_Err( p_aout, "too low audio sample frequency (%u)",
68 p_format->i_rate );
69 return -1;
72 aout_owner_t *owner = aout_owner(p_aout);
74 /* TODO: reduce lock scope depending on decoder's real need */
75 aout_OutputLock (p_aout);
77 /* Create the audio output stream */
78 owner->volume = aout_volume_New (p_aout, p_replay_gain);
80 atomic_store (&owner->restart, 0);
81 owner->input_format = *p_format;
82 owner->mixer_format = owner->input_format;
83 owner->request_vout = *p_request_vout;
85 var_Change (p_aout, "stereo-mode", VLC_VAR_SETVALUE,
86 &(vlc_value_t) { .i_int = owner->initial_stereo_mode }, NULL);
88 owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
89 if (aout_OutputNew (p_aout, &owner->mixer_format, &owner->filters_cfg))
90 goto error;
91 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
93 /* Create the audio filtering "input" pipeline */
94 owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
95 &owner->request_vout,
96 &owner->filters_cfg);
97 if (owner->filters == NULL)
99 aout_OutputDelete (p_aout);
100 error:
101 aout_volume_Delete (owner->volume);
102 owner->volume = NULL;
103 aout_OutputUnlock (p_aout);
104 return -1;
108 owner->sync.end = VLC_TS_INVALID;
109 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
110 owner->sync.discontinuity = true;
111 aout_OutputUnlock (p_aout);
113 atomic_init (&owner->buffers_lost, 0);
114 atomic_init (&owner->buffers_played, 0);
115 atomic_store (&owner->vp.update, true);
116 return 0;
120 * Stops all plugins involved in the audio output.
122 void aout_DecDelete (audio_output_t *aout)
124 aout_owner_t *owner = aout_owner (aout);
126 aout_OutputLock (aout);
127 if (owner->mixer_format.i_format)
129 aout_FiltersDelete (aout, owner->filters);
130 aout_OutputDelete (aout);
132 aout_volume_Delete (owner->volume);
133 owner->volume = NULL;
134 aout_OutputUnlock (aout);
137 static int aout_CheckReady (audio_output_t *aout)
139 aout_owner_t *owner = aout_owner (aout);
141 int status = AOUT_DEC_SUCCESS;
142 int restart = atomic_exchange (&owner->restart, 0);
143 if (unlikely(restart))
145 if (owner->mixer_format.i_format)
146 aout_FiltersDelete (aout, owner->filters);
148 if (restart & AOUT_RESTART_OUTPUT)
149 { /* Reinitializes the output */
150 msg_Dbg (aout, "restarting output...");
151 if (owner->mixer_format.i_format)
152 aout_OutputDelete (aout);
153 owner->mixer_format = owner->input_format;
154 owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
155 if (aout_OutputNew (aout, &owner->mixer_format, &owner->filters_cfg))
156 owner->mixer_format.i_format = 0;
157 aout_volume_SetFormat (owner->volume,
158 owner->mixer_format.i_format);
160 /* Notify the decoder that the aout changed in order to try a new
161 * suitable codec (like an HDMI audio format). However, keep the
162 * same codec if the aout was restarted because of a stereo-mode
163 * change from the user. */
164 if (!(restart & AOUT_RESTART_STEREOMODE))
165 status = AOUT_DEC_CHANGED;
168 msg_Dbg (aout, "restarting filters...");
169 owner->sync.end = VLC_TS_INVALID;
170 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
172 if (owner->mixer_format.i_format)
174 owner->filters = aout_FiltersNew (aout, &owner->input_format,
175 &owner->mixer_format,
176 &owner->request_vout,
177 &owner->filters_cfg);
178 if (owner->filters == NULL)
180 aout_OutputDelete (aout);
181 owner->mixer_format.i_format = 0;
184 /* TODO: This would be a good time to call clean up any video output
185 * left over by an audio visualization:
186 input_resource_TerminatVout(MAGIC HERE); */
188 return (owner->mixer_format.i_format) ? status : AOUT_DEC_FAILED;
192 * Marks the audio output for restart, to update any parameter of the output
193 * plug-in (e.g. output device or channel mapping).
195 void aout_RequestRestart (audio_output_t *aout, unsigned mode)
197 aout_owner_t *owner = aout_owner (aout);
198 atomic_fetch_or (&owner->restart, mode);
199 msg_Dbg (aout, "restart requested (%u)", mode);
203 * Buffer management
206 static void aout_StopResampling (audio_output_t *aout)
208 aout_owner_t *owner = aout_owner (aout);
210 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
211 aout_FiltersAdjustResampling (owner->filters, 0);
214 static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts)
216 aout_owner_t *owner = aout_owner (aout);
217 const audio_sample_format_t *fmt = &owner->mixer_format;
218 size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
220 block_t *block = block_Alloc (frames * fmt->i_bytes_per_frame
221 / fmt->i_frame_length);
222 if (unlikely(block == NULL))
223 return; /* uho! */
225 msg_Dbg (aout, "inserting %zu zeroes", frames);
226 memset (block->p_buffer, 0, block->i_buffer);
227 block->i_nb_samples = frames;
228 block->i_pts = pts;
229 block->i_dts = pts;
230 block->i_length = length;
231 aout_OutputPlay (aout, block);
234 static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
235 int input_rate)
237 aout_owner_t *owner = aout_owner (aout);
238 mtime_t drift;
241 * Depending on the drift between the actual and intended playback times,
242 * the audio core may ignore the drift, trigger upsampling or downsampling,
243 * insert silence or even discard samples.
244 * Future VLC versions may instead adjust the input rate.
246 * The audio output plugin is responsible for estimating its actual
247 * playback time, or rather the estimated time when the next sample will
248 * be played. (The actual playback time is always the current time, that is
249 * to say mdate(). It is not an useful statistic.)
251 * Most audio output plugins can estimate the delay until playback of
252 * the next sample to be written to the buffer, or equally the time until
253 * all samples in the buffer will have been played. Then:
254 * pts = mdate() + delay
256 if (aout_OutputTimeGet (aout, &drift) != 0)
257 return; /* nothing can be done if timing is unknown */
258 drift += mdate () - dec_pts;
260 /* Late audio output.
261 * This can happen due to insufficient caching, scheduling jitter
262 * or bug in the decoder. Ideally, the output would seek backward. But that
263 * is not portable, not supported by some hardware and often unsafe/buggy
264 * where supported. The other alternative is to flush the buffers
265 * completely. */
266 if (drift > (owner->sync.discontinuity ? 0
267 : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
269 if (!owner->sync.discontinuity)
270 msg_Warn (aout, "playback way too late (%"PRId64"): "
271 "flushing buffers", drift);
272 else
273 msg_Dbg (aout, "playback too late (%"PRId64"): "
274 "flushing buffers", drift);
275 aout_OutputFlush (aout, false);
277 aout_StopResampling (aout);
278 owner->sync.end = VLC_TS_INVALID;
279 owner->sync.discontinuity = true;
281 /* Now the output might be too early... Recheck. */
282 if (aout_OutputTimeGet (aout, &drift) != 0)
283 return; /* nothing can be done if timing is unknown */
284 drift += mdate () - dec_pts;
287 /* Early audio output.
288 * This is rare except at startup when the buffers are still empty. */
289 if (drift < (owner->sync.discontinuity ? 0
290 : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
292 if (!owner->sync.discontinuity)
293 msg_Warn (aout, "playback way too early (%"PRId64"): "
294 "playing silence", drift);
295 aout_DecSilence (aout, -drift, dec_pts);
297 aout_StopResampling (aout);
298 owner->sync.discontinuity = true;
299 drift = 0;
302 if (!aout_FiltersCanResample(owner->filters))
303 return;
305 /* Resampling */
306 if (drift > +AOUT_MAX_PTS_DELAY
307 && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
309 msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
310 drift);
311 owner->sync.resamp_type = AOUT_RESAMPLING_UP;
312 owner->sync.resamp_start_drift = +drift;
314 if (drift < -AOUT_MAX_PTS_ADVANCE
315 && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
317 msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
318 drift);
319 owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
320 owner->sync.resamp_start_drift = -drift;
323 if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
324 return; /* Everything is fine. Nothing to do. */
326 if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
327 { /* If the drift is ever increasing, then something is seriously wrong.
328 * Cease resampling and hope for the best. */
329 msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
330 "stopping resampling", drift);
331 aout_StopResampling (aout);
332 return;
335 /* Resampling has been triggered earlier. This checks if it needs to be
336 * increased or decreased. Resampling rate changes must be kept slow for
337 * the comfort of listeners. */
338 int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
340 if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
341 /* If the drift has been reduced from more than half its initial
342 * value, then it is time to switch back the resampling direction. */
343 adj *= -1;
345 if (!aout_FiltersAdjustResampling (owner->filters, adj))
346 { /* Everything is back to normal: stop resampling. */
347 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
348 msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
352 /*****************************************************************************
353 * aout_DecPlay : filter & mix the decoded buffer
354 *****************************************************************************/
355 int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
357 aout_owner_t *owner = aout_owner (aout);
359 assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
360 assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
361 assert (block->i_pts >= VLC_TS_0);
363 block->i_length = CLOCK_FREQ * block->i_nb_samples
364 / owner->input_format.i_rate;
366 aout_OutputLock (aout);
367 int ret = aout_CheckReady (aout);
368 if (unlikely(ret == AOUT_DEC_FAILED))
369 goto drop; /* Pipeline is unrecoverably broken :-( */
371 const mtime_t now = mdate (), advance = block->i_pts - now;
372 if (advance < -AOUT_MAX_PTS_DELAY)
373 { /* Late buffer can be caused by bugs in the decoder, by scheduling
374 * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
375 * insufficient. We assume the PTS is wrong and play the buffer anyway:
376 * Hopefully video has encountered a similar PTS problem as audio. */
377 msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
378 goto drop;
380 if (advance > AOUT_MAX_ADVANCE_TIME)
381 { /* Early buffers can only be caused by bugs in the decoder. */
382 msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
383 goto drop;
385 if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
386 owner->sync.discontinuity = true;
388 if (atomic_exchange(&owner->vp.update, false))
390 vlc_mutex_lock (&owner->vp.lock);
391 aout_FiltersChangeViewpoint (owner->filters, &owner->vp.value);
392 vlc_mutex_unlock (&owner->vp.lock);
395 block = aout_FiltersPlay (owner->filters, block, input_rate);
396 if (block == NULL)
397 goto lost;
399 /* Software volume */
400 aout_volume_Amplify (owner->volume, block);
402 /* Drift correction */
403 aout_DecSynchronize (aout, block->i_pts, input_rate);
405 /* Output */
406 owner->sync.end = block->i_pts + block->i_length + 1;
407 owner->sync.discontinuity = false;
408 aout_OutputPlay (aout, block);
409 atomic_fetch_add(&owner->buffers_played, 1);
410 out:
411 aout_OutputUnlock (aout);
412 return ret;
413 drop:
414 owner->sync.discontinuity = true;
415 block_Release (block);
416 lost:
417 atomic_fetch_add(&owner->buffers_lost, 1);
418 goto out;
421 void aout_DecGetResetStats(audio_output_t *aout, unsigned *restrict lost,
422 unsigned *restrict played)
424 aout_owner_t *owner = aout_owner (aout);
426 *lost = atomic_exchange(&owner->buffers_lost, 0);
427 *played = atomic_exchange(&owner->buffers_played, 0);
430 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
432 aout_owner_t *owner = aout_owner (aout);
434 aout_OutputLock (aout);
435 if (owner->sync.end != VLC_TS_INVALID)
437 if (paused)
438 owner->sync.end -= date;
439 else
440 owner->sync.end += date;
442 if (owner->mixer_format.i_format)
443 aout_OutputPause (aout, paused, date);
444 aout_OutputUnlock (aout);
447 void aout_DecFlush (audio_output_t *aout, bool wait)
449 aout_owner_t *owner = aout_owner (aout);
451 aout_OutputLock (aout);
452 owner->sync.end = VLC_TS_INVALID;
453 if (owner->mixer_format.i_format)
455 if (wait)
457 block_t *block = aout_FiltersDrain (owner->filters);
458 if (block)
459 aout_OutputPlay (aout, block);
461 else
462 aout_FiltersFlush (owner->filters);
463 aout_OutputFlush (aout, wait);
465 aout_OutputUnlock (aout);
468 void aout_ChangeViewpoint(audio_output_t *aout,
469 const vlc_viewpoint_t *p_viewpoint)
471 aout_owner_t *owner = aout_owner (aout);
473 vlc_mutex_lock (&owner->vp.lock);
474 owner->vp.value = *p_viewpoint;
475 atomic_store(&owner->vp.update, true);
476 vlc_mutex_unlock (&owner->vp.lock);