vlc | branch: master | Thomas Guillem <[email protected]> | Thu Mar 7 15:40:27 2019 +0100| [a3e4cb4a907f5fdbface2c4a1012461fc4382f92] | committer: Thomas Guillem
aout: use vlc_clock_t During the transition, the clock argument is not mandatory. If the clock is NULL, the aout will use ts from the block_t that were converted from the decoder. Co-authored-by: Rémi Denis-Courmont <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a3e4cb4a907f5fdbface2c4a1012461fc4382f92 --- src/audio_output/aout_internal.h | 7 ++- src/audio_output/dec.c | 132 ++++++++++++++++++++++++++++++++------- src/input/decoder.c | 2 +- 3 files changed, 116 insertions(+), 25 deletions(-) diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h index 7cf7a83e68..1dd92e96aa 100644 --- a/src/audio_output/aout_internal.h +++ b/src/audio_output/aout_internal.h @@ -63,10 +63,14 @@ typedef struct struct { + struct vlc_clock_t *clock; float rate; /**< Play-out speed rate */ vlc_tick_t resamp_start_drift; /**< Resampler drift absolute value */ int resamp_type; /**< Resampler mode (FIXME: redundant / resampling) */ bool discontinuity; + vlc_tick_t request_delay; + vlc_tick_t delay; + vlc_tick_t first_pts; } sync; vlc_tick_t original_pts; @@ -129,12 +133,13 @@ void aout_FormatsPrint(vlc_object_t *, const char *, #define AOUT_DEC_FAILED VLC_EGENERIC int aout_DecNew(audio_output_t *, const audio_sample_format_t *, - const audio_replay_gain_t *); + struct vlc_clock_t *clock, const audio_replay_gain_t *); void aout_DecDelete(audio_output_t *); int aout_DecPlay(audio_output_t *aout, block_t *block); void aout_DecGetResetStats(audio_output_t *, unsigned *, unsigned *); void aout_DecChangePause(audio_output_t *, bool b_paused, vlc_tick_t i_date); void aout_DecChangeRate(audio_output_t *aout, float rate); +void aout_DecChangeDelay(audio_output_t *aout, vlc_tick_t delay); void aout_DecFlush(audio_output_t *, bool wait); void aout_RequestRestart (audio_output_t *, unsigned); void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts, diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c index cde1caaef9..6b79b249b6 100644 --- a/src/audio_output/dec.c +++ b/src/audio_output/dec.c @@ -1,7 +1,7 @@ /***************************************************************************** * dec.c : audio output API towards decoders ***************************************************************************** - * Copyright (C) 2002-2007 VLC authors and VideoLAN + * Copyright (C) 2002-2019 VLC authors, VideoLAN and Videolabs SAS * * Authors: Christophe Massiot <[email protected]> * @@ -35,14 +35,14 @@ #include <vlc_aout.h> #include "aout_internal.h" +#include "clock/clock.h" #include "libvlc.h" /** * Creates an audio output */ -int aout_DecNew(audio_output_t *p_aout, - const audio_sample_format_t *p_format, - const audio_replay_gain_t *p_replay_gain) +int aout_DecNew(audio_output_t *p_aout, const audio_sample_format_t *p_format, + vlc_clock_t *clock, const audio_replay_gain_t *p_replay_gain) { assert(p_aout); assert(p_format); @@ -80,6 +80,7 @@ int aout_DecNew(audio_output_t *p_aout, atomic_store_explicit(&owner->restart, 0, memory_order_relaxed); owner->input_format = *p_format; owner->mixer_format = owner->input_format; + owner->sync.clock = clock; owner->filters_cfg = AOUT_FILTERS_CFG_INIT; if (aout_OutputNew (p_aout, &owner->mixer_format, &owner->filters_cfg)) @@ -87,8 +88,9 @@ int aout_DecNew(audio_output_t *p_aout, aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format); /* Create the audio filtering "input" pipeline */ - owner->filters = aout_FiltersNew(p_aout, p_format, &owner->mixer_format, - &owner->filters_cfg); + owner->filters = aout_FiltersNewWithClock(VLC_OBJECT(p_aout), clock, p_format, + &owner->mixer_format, + &owner->filters_cfg); if (owner->filters == NULL) { aout_OutputDelete (p_aout); @@ -102,6 +104,7 @@ error: owner->sync.resamp_type = AOUT_RESAMPLING_NONE; owner->sync.discontinuity = true; owner->original_pts = VLC_TICK_INVALID; + owner->sync.delay = owner->sync.request_delay = 0; atomic_init (&owner->buffers_lost, 0); atomic_init (&owner->buffers_played, 0); @@ -162,14 +165,17 @@ static int aout_CheckReady (audio_output_t *aout) if (owner->mixer_format.i_format) { - owner->filters = aout_FiltersNew(aout, &owner->input_format, - &owner->mixer_format, - &owner->filters_cfg); + owner->filters = aout_FiltersNewWithClock(VLC_OBJECT(aout), + owner->sync.clock, + &owner->input_format, + &owner->mixer_format, + &owner->filters_cfg); if (owner->filters == NULL) { aout_OutputDelete (aout); owner->mixer_format.i_format = 0; } + aout_FiltersSetClockDelay(owner->filters, owner->sync.delay); } /* TODO: This would be a good time to call clean up any video output * left over by an audio visualization: @@ -201,6 +207,8 @@ static void aout_StopResampling (audio_output_t *aout) aout_FiltersAdjustResampling (owner->filters, 0); } +static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t system_now, + vlc_tick_t dec_pts); static void aout_DecSilence (audio_output_t *aout, vlc_tick_t length, vlc_tick_t pts) { aout_owner_t *owner = aout_owner (aout); @@ -218,14 +226,17 @@ static void aout_DecSilence (audio_output_t *aout, vlc_tick_t length, vlc_tick_t block->i_pts = pts; block->i_dts = pts; block->i_length = length; - aout->play(aout, block, pts); + + const vlc_tick_t system_now = vlc_tick_now(); + const vlc_tick_t system_pts = !owner->sync.clock ? pts : + vlc_clock_ConvertToSystem(owner->sync.clock, system_now, pts, + owner->sync.rate); + aout->play(aout, block, system_pts); } -static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t dec_pts) +static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t system_now, + vlc_tick_t dec_pts) { - vlc_tick_t now = vlc_tick_now(); - vlc_tick_t delay; - /** * Depending on the drift between the actual and intended playback times, * the audio core may ignore the drift, trigger upsampling or downsampling, @@ -242,18 +253,45 @@ static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t dec_pts) * all samples in the buffer will have been played. Then: * pts = vlc_tick_now() + delay */ + aout_owner_t *owner = aout_owner (aout); + vlc_tick_t delay; + if (aout->time_get(aout, &delay) != 0) return; /* nothing can be done if timing is unknown */ - aout_RequestRetiming(aout, now, dec_pts - delay); + if (owner->sync.discontinuity && owner->sync.clock) + { + /* Chicken-egg situation for most aout modules that can't be started + * deferred (all except PulseAudio). These modules will start to play + * data immediately and ignore the given play_date (that take the clock + * jitter into account). We don't want to let aout_RequestRetiming() + * handle the first silence (from the "Early audio output" case) since + * this function will first update the clock without taking the jitter + * into account. Therefore, we manually insert silence that correspond + * to the clock jitter value before updating the clock. + */ + vlc_tick_t play_date = + vlc_clock_ConvertToSystem(owner->sync.clock, system_now + delay, + dec_pts, owner->sync.rate); + vlc_tick_t jitter = play_date - system_now; + if (jitter > 0) + { + aout_DecSilence (aout, jitter, dec_pts - delay); + if (aout->time_get(aout, &delay) != 0) + return; + } + } + + aout_RequestRetiming(aout, system_now + delay, dec_pts); } void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts, vlc_tick_t audio_ts) { aout_owner_t *owner = aout_owner (aout); - const float rate = owner->sync.rate; - vlc_tick_t drift = system_ts - audio_ts; + float rate = owner->sync.rate; + vlc_tick_t drift = !owner->sync.clock ? system_ts - audio_ts : + -vlc_clock_Update(owner->sync.clock, system_ts, audio_ts, rate); /* Late audio output. * This can happen due to insufficient caching, scheduling jitter @@ -274,7 +312,7 @@ void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts, aout_StopResampling (aout); return; /* nothing can be done if timing is unknown */ -} + } /* Early audio output. * This is rare except at startup when the buffers are still empty. */ @@ -384,16 +422,33 @@ int aout_DecPlay(audio_output_t *aout, block_t *block) if (block == NULL) return ret; + const vlc_tick_t original_pts = owner->original_pts; + owner->original_pts = VLC_TICK_INVALID; + /* Software volume */ aout_volume_Amplify (owner->volume, block); + /* Update delay */ + if (owner->sync.clock && owner->sync.request_delay != owner->sync.delay) + { + owner->sync.delay = owner->sync.request_delay; + vlc_tick_t delta = vlc_clock_SetDelay(owner->sync.clock, owner->sync.delay); + aout_FiltersSetClockDelay(owner->filters, owner->sync.delay); + if (delta > 0) + aout_DecSilence (aout, delta, block->i_pts); + } + /* Drift correction */ - aout_DecSynchronize(aout, owner->original_pts); + vlc_tick_t system_now = vlc_tick_now(); + aout_DecSynchronize(aout, system_now, original_pts); + const vlc_tick_t play_date = !owner->sync.clock ? original_pts : + vlc_clock_ConvertToSystem(owner->sync.clock, system_now, original_pts, + owner->sync.rate); /* Output */ owner->sync.discontinuity = false; - aout->play(aout, block, owner->original_pts); - owner->original_pts = VLC_TICK_INVALID; + aout->play(aout, block, play_date); + atomic_fetch_add_explicit(&owner->buffers_played, 1, memory_order_relaxed); return ret; drop: @@ -420,7 +475,12 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, vlc_tick_t date) aout_owner_t *owner = aout_owner (aout); if (owner->mixer_format.i_format) - aout->pause(aout, paused, date); + { + if (aout->pause != NULL) + aout->pause(aout, paused, date); + else if (paused) + aout->flush(aout, false); + } } void aout_DecChangeRate(audio_output_t *aout, float rate) @@ -430,6 +490,13 @@ void aout_DecChangeRate(audio_output_t *aout, float rate) owner->sync.rate = rate; } +void aout_DecChangeDelay(audio_output_t *aout, vlc_tick_t delay) +{ + aout_owner_t *owner = aout_owner(aout); + + owner->sync.request_delay = delay; +} + void aout_DecFlush (audio_output_t *aout, bool wait) { aout_owner_t *owner = aout_owner (aout); @@ -440,12 +507,31 @@ void aout_DecFlush (audio_output_t *aout, bool wait) { block_t *block = aout_FiltersDrain (owner->filters); if (block) - aout->play(aout, block, block->i_pts); + aout->play(aout, block, vlc_tick_now()); } else aout_FiltersFlush (owner->filters); aout->flush(aout, wait); + if (owner->sync.clock) + { + vlc_clock_Reset(owner->sync.clock); + aout_FiltersResetClock(owner->filters); + } + + if (owner->sync.clock && owner->sync.delay > 0) + { + /* Also reset the delay in case of a positive delay. This will + * trigger a silence playback before the next play. Consequently, + * the first play date won't be (delay + dejitter) but only + * dejitter. This will allow the aout to update the master clock + * sooner. + */ + vlc_clock_SetDelay(owner->sync.clock, 0); + aout_FiltersSetClockDelay(owner->filters, 0); + owner->sync.request_delay = owner->sync.delay; + owner->sync.delay = 0; + } } owner->sync.discontinuity = true; owner->original_pts = VLC_TICK_INVALID; diff --git a/src/input/decoder.c b/src/input/decoder.c index 096340f34b..a3b55d85fe 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -345,7 +345,7 @@ static int aout_update_format( decoder_t *p_dec ) if( p_dec->fmt_out.i_codec == VLC_CODEC_DTS ) var_SetBool( p_aout, "dtshd", p_dec->fmt_out.i_profile > 0 ); - if( aout_DecNew( p_aout, &format, + if( aout_DecNew( p_aout, &format, NULL, &p_dec->fmt_out.audio_replay_gain ) ) { input_resource_PutAout( p_owner->p_resource, p_aout ); _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
