Skip to content

Commit

Permalink
input: decoder: fix drain/flush execution order
Browse files Browse the repository at this point in the history
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 34a548c

Fixes #27499
  • Loading branch information
tguillem authored and jbkempf committed Dec 3, 2022
1 parent f55b5b5 commit 037edac
Showing 1 changed file with 9 additions and 7 deletions.
16 changes: 9 additions & 7 deletions src/input/decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}

Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit 037edac

Please sign in to comment.