From 037edac375bd08e7bbe7346fd6fd1f060816bc93 Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Wed, 30 Nov 2022 17:32:32 +0100 Subject: [PATCH] input: decoder: fix drain/flush execution order This fixes a possible (but unlikely) assert, from vlc_aout_stream_Drain(): assert(atomic_load_explicit(&stream->drain_deadline, memory_order_relaxed) == VLC_TICK_INVALID); It can happen when vlc_aout_stream_Drain() is called more than time in a row, that is illegal: Drain should be the last command or can be cancelled by a Flush to continue the playback. If drain and flush are called in that order - vlc_input_decoder_Drain() - vlc_input_decoder_Flush() - vlc_input_decoder_Drain() It was possible that vlc_aout_stream_Flush() was called before the first vlc_input_decoder_Drain(). To fix this issue, cancel the draining state when flushing the decoder and do check that the decoder is still draining after unlocking/locking (after draining the decoder module). Regression from 34a548cc02ce67920efbd7fdaa5af752199236a8 Fixes #27499 --- src/input/decoder.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/input/decoder.c b/src/input/decoder.c index af3d91fd53bd..1ec4044a4e9e 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -1791,16 +1791,17 @@ static void *DecoderThread( void *p_data ) DecoderThread_ProcessInput( p_owner, frame ); vlc_fifo_Lock(p_owner->p_fifo); - if( frame == NULL && p_owner->dec.fmt_in->i_cat == AUDIO_ES ) - { /* Draining: the decoder is drained and all decoded buffers are - * queued to the output at this point. Now drain the output. */ - if( p_owner->p_astream != NULL ) + if( p_owner->b_draining && frame == NULL ) + { + p_owner->b_draining = false; + + if( p_owner->dec.fmt_in->i_cat == AUDIO_ES && p_owner->p_astream != NULL ) + { /* Draining: the decoder is drained and all decoded buffers are + * queued to the output at this point. Now drain the output. */ vlc_aout_stream_Drain( p_owner->p_astream ); + } } - /* TODO? Wait for draining instead of polling. */ - if( p_owner->b_draining && (frame == NULL) ) - p_owner->b_draining = false; vlc_cond_signal( &p_owner->wait_acknowledge ); } @@ -2386,6 +2387,7 @@ void vlc_input_decoder_Flush( vlc_input_decoder_t *p_owner ) * dequeued by DecoderThread and there is no need to flush a second time in * a row. */ p_owner->flushing = true; + p_owner->b_draining = false; /* Flush video/spu decoder when paused: increment frames_countdown in order * to display one frame/subtitle */