X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Faudio_output%2Fdec.c;h=74440728958b99b98bfa0e09b5e0cd51c1455be4;hb=90a41800049ec54a0191613fdfb37c3338d9d297;hp=2ec340a33588d3f0f842269438f6547201039cd5;hpb=ff89ff37090060aca89e455fb36d8a9863357ec0;p=vlc diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c index 2ec340a335..7444072895 100644 --- a/src/audio_output/dec.c +++ b/src/audio_output/dec.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "aout_internal.h" #include "libvlc.h" @@ -53,7 +52,7 @@ int aout_DecNew( audio_output_t *p_aout, return -1; } - if( p_format->i_rate > 192000 ) + if( p_format->i_rate > 352800 ) { msg_Err( p_aout, "excessive audio sample frequency (%u)", p_format->i_rate ); @@ -69,36 +68,38 @@ int aout_DecNew( audio_output_t *p_aout, aout_owner_t *owner = aout_owner(p_aout); /* TODO: reduce lock scope depending on decoder's real need */ - aout_lock( p_aout ); + aout_OutputLock (p_aout); var_Destroy( p_aout, "stereo-mode" ); /* Create the audio output stream */ owner->volume = aout_volume_New (p_aout, p_replay_gain); - vlc_atomic_set (&owner->restart, 0); + atomic_store (&owner->restart, 0); owner->input_format = *p_format; owner->mixer_format = owner->input_format; + owner->request_vout = *p_request_vout; if (aout_OutputNew (p_aout, &owner->mixer_format)) goto error; aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format); /* Create the audio filtering "input" pipeline */ - if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format, - p_request_vout)) + owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format, + &owner->request_vout); + if (owner->filters == NULL) { aout_OutputDelete (p_aout); error: aout_volume_Delete (owner->volume); - aout_unlock (p_aout); + aout_OutputUnlock (p_aout); return -1; } owner->sync.end = VLC_TS_INVALID; owner->sync.resamp_type = AOUT_RESAMPLING_NONE; owner->sync.discontinuity = true; - aout_unlock( p_aout ); + aout_OutputUnlock (p_aout); atomic_init (&owner->buffers_lost, 0); return 0; @@ -107,137 +108,86 @@ error: /** * Stops all plugins involved in the audio output. */ -void aout_DecDelete (audio_output_t *p_aout) -{ - aout_owner_t *owner = aout_owner (p_aout); - - aout_lock( p_aout ); - aout_FiltersDelete (p_aout); - aout_OutputDelete( p_aout ); - aout_volume_Delete (owner->volume); - - var_Destroy( p_aout, "stereo-mode" ); - - aout_unlock( p_aout ); -} - -#define AOUT_RESTART_OUTPUT 1 -#define AOUT_RESTART_INPUT 2 -static int aout_CheckRestart (audio_output_t *aout) +void aout_DecDelete (audio_output_t *aout) { aout_owner_t *owner = aout_owner (aout); - aout_assert_locked (aout); - - int restart = vlc_atomic_swap (&owner->restart, 0); - if (likely(restart == 0)) - return 0; - - assert (restart & AOUT_RESTART_INPUT); - - const aout_request_vout_t request_vout = owner->request_vout; - - aout_FiltersDelete (aout); - - /* Reinitializes the output */ - if (restart & AOUT_RESTART_OUTPUT) + aout_OutputLock (aout); + if (owner->mixer_format.i_format) { + aout_FiltersDelete (aout, owner->filters); aout_OutputDelete (aout); - owner->mixer_format = owner->input_format; - if (aout_OutputNew (aout, &owner->mixer_format)) - abort (); /* FIXME we are officially screwed */ - aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format); } - - owner->sync.end = VLC_TS_INVALID; - owner->sync.resamp_type = AOUT_RESAMPLING_NONE; - - if (aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format, - &request_vout)) - { - abort (); /* FIXME */ - } - return 0; + aout_volume_Delete (owner->volume); + aout_OutputUnlock (aout); + var_Destroy (aout, "stereo-mode"); } -/** - * Marks the audio output for restart, to update any parameter of the output - * plug-in (e.g. output device or channel mapping). - */ -static void aout_RequestRestart (audio_output_t *aout) +static int aout_CheckReady (audio_output_t *aout) { aout_owner_t *owner = aout_owner (aout); - /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */ - vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT); -} - -int aout_ChannelsRestart (vlc_object_t *obj, const char *varname, - vlc_value_t oldval, vlc_value_t newval, void *data) -{ - audio_output_t *aout = (audio_output_t *)obj; - (void)oldval; (void)newval; (void)data; - - if (!strcmp (varname, "audio-device")) + int restart = atomic_exchange (&owner->restart, 0); + if (unlikely(restart)) { - /* This is supposed to be a significant change and supposes - * rebuilding the channel choices. */ - var_Destroy (aout, "stereo-mode"); + if (owner->mixer_format.i_format) + aout_FiltersDelete (aout, owner->filters); + + if (restart & AOUT_RESTART_OUTPUT) + { /* Reinitializes the output */ + msg_Dbg (aout, "restarting output..."); + if (owner->mixer_format.i_format) + aout_OutputDelete (aout); + owner->mixer_format = owner->input_format; + if (aout_OutputNew (aout, &owner->mixer_format)) + owner->mixer_format.i_format = 0; + aout_volume_SetFormat (owner->volume, + owner->mixer_format.i_format); + } + + msg_Dbg (aout, "restarting filters..."); + owner->sync.end = VLC_TS_INVALID; + owner->sync.resamp_type = AOUT_RESAMPLING_NONE; + + if (owner->mixer_format.i_format) + { + owner->filters = aout_FiltersNew (aout, &owner->input_format, + &owner->mixer_format, + &owner->request_vout); + if (owner->filters == NULL) + { + aout_OutputDelete (aout); + owner->mixer_format.i_format = 0; + } + } + /* TODO: This would be a good time to call clean up any video output + * left over by an audio visualization: + input_resource_TerminatVout(MAGIC HERE); */ } - aout_RequestRestart (aout); - return 0; + return (owner->mixer_format.i_format) ? 0 : -1; } /** - * This function will safely mark aout input to be restarted as soon as - * possible to take configuration changes into account + * Marks the audio output for restart, to update any parameter of the output + * plug-in (e.g. output device or channel mapping). */ -void aout_InputRequestRestart (audio_output_t *aout) +void aout_RequestRestart (audio_output_t *aout, unsigned mode) { aout_owner_t *owner = aout_owner (aout); - - vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT); + atomic_fetch_or (&owner->restart, mode); + msg_Dbg (aout, "restart requested (%u)", mode); } - /* * Buffer management */ -/***************************************************************************** - * aout_DecNewBuffer : ask for a new empty buffer - *****************************************************************************/ -block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples) -{ - /* NOTE: the caller is responsible for serializing input change */ - aout_owner_t *owner = aout_owner (aout); - - size_t length = samples * owner->input_format.i_bytes_per_frame - / owner->input_format.i_frame_length; - block_t *block = block_Alloc( length ); - if( likely(block != NULL) ) - { - block->i_nb_samples = samples; - block->i_pts = block->i_length = 0; - } - return block; -} - -/***************************************************************************** - * aout_DecDeleteBuffer : destroy an undecoded buffer - *****************************************************************************/ -void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block) -{ - (void) aout; - block_Release (block); -} - static void aout_StopResampling (audio_output_t *aout) { aout_owner_t *owner = aout_owner (aout); owner->sync.resamp_type = AOUT_RESAMPLING_NONE; - aout_FiltersAdjustResampling (aout, 0); + aout_FiltersAdjustResampling (owner->filters, 0); } static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts) @@ -267,7 +217,7 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts, int input_rate) { aout_owner_t *owner = aout_owner (aout); - mtime_t aout_pts, drift; + mtime_t drift; /** * Depending on the drift between the actual and intended playback times, @@ -285,9 +235,9 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts, * all samples in the buffer will have been played. Then: * pts = mdate() + delay */ - if (aout_OutputTimeGet (aout, &aout_pts) != 0) + if (aout_OutputTimeGet (aout, &drift) != 0) return; /* nothing can be done if timing is unknown */ - drift = aout_pts - dec_pts; + drift += mdate () - dec_pts; /* Late audio output. * This can happen due to insufficient caching, scheduling jitter @@ -311,9 +261,9 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts, owner->sync.discontinuity = true; /* Now the output might be too early... Recheck. */ - if (aout_OutputTimeGet (aout, &aout_pts) != 0) + if (aout_OutputTimeGet (aout, &drift) != 0) return; /* nothing can be done if timing is unknown */ - drift = aout_pts - dec_pts; + drift += mdate () - dec_pts; } /* Early audio output. @@ -371,7 +321,7 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts, * value, then it is time to switch back the resampling direction. */ adj *= -1; - if (!aout_FiltersAdjustResampling (aout, adj)) + if (!aout_FiltersAdjustResampling (owner->filters, adj)) { /* Everything is back to normal: stop resampling. */ owner->sync.resamp_type = AOUT_RESAMPLING_NONE; msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift); @@ -392,8 +342,8 @@ int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate) block->i_length = CLOCK_FREQ * block->i_nb_samples / owner->input_format.i_rate; - aout_lock (aout); - if (unlikely(aout_CheckRestart (aout))) + aout_OutputLock (aout); + if (unlikely(aout_CheckReady (aout))) goto drop; /* Pipeline is unrecoverably broken :-( */ const mtime_t now = mdate (), advance = block->i_pts - now; @@ -413,7 +363,7 @@ int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate) if (block->i_flags & BLOCK_FLAG_DISCONTINUITY) owner->sync.discontinuity = true; - block = aout_FiltersPlay (aout, block, input_rate); + block = aout_FiltersPlay (owner->filters, block, input_rate); if (block == NULL) goto lost; @@ -428,7 +378,7 @@ int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate) owner->sync.discontinuity = false; aout_OutputPlay (aout, block); out: - aout_unlock (aout); + aout_OutputUnlock (aout); return 0; drop: owner->sync.discontinuity = true; @@ -448,7 +398,7 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date) { aout_owner_t *owner = aout_owner (aout); - aout_lock (aout); + aout_OutputLock (aout); if (owner->sync.end != VLC_TS_INVALID) { if (paused) @@ -456,18 +406,20 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date) else owner->sync.end += date; } - aout_OutputPause (aout, paused, date); - aout_unlock (aout); + if (owner->mixer_format.i_format) + aout_OutputPause (aout, paused, date); + aout_OutputUnlock (aout); } -void aout_DecFlush (audio_output_t *aout) +void aout_DecFlush (audio_output_t *aout, bool wait) { aout_owner_t *owner = aout_owner (aout); - aout_lock (aout); + aout_OutputLock (aout); owner->sync.end = VLC_TS_INVALID; - aout_OutputFlush (aout, false); - aout_unlock (aout); + if (owner->mixer_format.i_format) + aout_OutputFlush (aout, wait); + aout_OutputUnlock (aout); } bool aout_DecIsEmpty (audio_output_t *aout) @@ -476,14 +428,14 @@ bool aout_DecIsEmpty (audio_output_t *aout) mtime_t now = mdate (); bool empty = true; - aout_lock (aout); + aout_OutputLock (aout); if (owner->sync.end != VLC_TS_INVALID) empty = owner->sync.end <= now; - if (empty) + if (empty && owner->mixer_format.i_format) /* The last PTS has elapsed already. So the underlying audio output * buffer should be empty or almost. Thus draining should be fast * and will not block the caller too long. */ aout_OutputFlush (aout, true); - aout_unlock (aout); + aout_OutputUnlock (aout); return empty; }