[vlc-commits] [Git][videolan/vlc][master] 4 commits: decoder: acknowledge all pause requests
Steve Lhomme (@robUx4)
gitlab at videolan.org
Wed Jul 8 11:17:29 UTC 2026
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
7e78a995 by Thomas Guillem at 2026-07-08T10:45:04+00:00
decoder: acknowledge all pause requests
A pause and a resume requested in quick succession can cancel each other
out before the decoder thread wakes up: the output ends up in the
correct state but the last request is never acknowledged. Each pause
request will now produce a pause event.
Fixes #29960
(test_src_player_pause hangs, ~2% of runs with 100 parallel instances)
- - - - -
ef2f3434 by Thomas Guillem at 2026-07-08T10:45:04+00:00
player: pass a valid date to the PLAYING timer event
input->pause_date is reset just before being passed, so the PLAYING
timer event always carried VLC_TICK_INVALID. The date is unused for
this event so far; the next commit needs it.
- - - - -
aaf1673e by Thomas Guillem at 2026-07-08T10:45:04+00:00
player: timer: don't update the state from stale pause events
A pause acknowledgement from an ES output use the same request date and
can be delivered after that pause was resumed. Don't update the timer
state from it: the state follows the input timeline. It is still
reported to the source: events of a given ES are delivered in order, a
late pause is delayed, never reordered.
Replace the pause_reported flag with the date of the last reported
pause. No more reset on PLAYING: clearing it while an acknowledgement
was in flight was reporting a stale pause and eating the next one.
Fixes the following assert in `test_src_player_pause` (20% repro rate
since `--start-paused` fixes, but unrelated):
```
test_src_player_pause: ../../test/src/player/pause.c:101: test_pause: Assertion `get_timer_report(player, &video_timer).type == REPORT_TIMER_PAUSED' failed.
```
- - - - -
0567f08a by Thomas Guillem at 2026-07-08T10:45:04+00:00
test: player: pause: check the date of the second pause
A stale report from the first pause could satisfy the type-only wait.
- - - - -
5 changed files:
- src/input/decoder.c
- src/player/input.c
- src/player/player.h
- src/player/timer.c
- test/src/player/pause.c
Changes:
=====================================
src/input/decoder.c
=====================================
@@ -225,7 +225,7 @@ struct vlc_input_decoder_t
#define PREROLL_FORCED VLC_TICK_MAX
/* Pause & Rate */
- vlc_tick_t pause_date;
+ vlc_tick_t pause_date, output_pause_date;
vlc_tick_t delay, output_delay;
float rate, output_rate;
int frames_countdown;
@@ -2011,9 +2011,16 @@ static void *DecoderThread( void *p_data )
continue;
}
- if( p_owner->paused != p_owner->output_paused )
+ /* Also compare the request dates: a pause and a resume requested in
+ * quick succession can cancel each other out, but each request must
+ * still be acknowledged via decoder_Notify() */
+ if( p_owner->paused != p_owner->output_paused
+ || p_owner->pause_date != p_owner->output_pause_date )
{ /* Update playing/paused status of the output */
- Decoder_ChangeOutputPause( p_owner, p_owner->paused, p_owner->pause_date );
+ if( p_owner->paused != p_owner->output_paused )
+ Decoder_ChangeOutputPause( p_owner, p_owner->paused,
+ p_owner->pause_date );
+ p_owner->output_pause_date = p_owner->pause_date;
decoder_Notify(p_owner, on_output_paused, p_owner->paused,
p_owner->pause_date);
if (unlikely(p_owner->paused && p_owner->cat == VIDEO_ES
@@ -2182,7 +2189,7 @@ CreateDecoder( vlc_object_t *p_parent, const struct vlc_input_decoder_cfg *cfg )
p_owner->output_delay = p_owner->delay = 0;
p_owner->output_rate = p_owner->rate = 1.f;
p_owner->output_paused = p_owner->paused = false;
- p_owner->pause_date = VLC_TICK_INVALID;
+ p_owner->output_pause_date = p_owner->pause_date = VLC_TICK_INVALID;
p_owner->frames_countdown = 0;
p_owner->b_waiting = false;
=====================================
src/player/input.c
=====================================
@@ -299,7 +299,7 @@ vlc_player_input_HandleState(struct vlc_player_input *input,
vlc_player_SignalAtoBLoop(player);
vlc_player_UpdateTimerEvent(player, NULL,
VLC_PLAYER_TIMER_EVENT_PLAYING,
- input->pause_date);
+ state_date);
/* fall through */
case VLC_PLAYER_STATE_STARTED:
if (player->started &&
=====================================
src/player/player.h
=====================================
@@ -196,10 +196,9 @@ struct vlc_player_timer_source
struct vlc_player_timer_point point;
bool seeking;
- /* Set once a pause has been reported to this source's listener.
- * The input might signal paused clock and then output
- * would signal it. This flag filters this case here. */
- bool pause_reported;
+ /* Date of the last reported pause, to report a pause signaled by both
+ * the input and the output only once */
+ vlc_tick_t reported_pause_date;
union
{
@@ -243,6 +242,9 @@ struct vlc_player_timer
UPDATE_STATE_RESUMING,
} update_state;
vlc_tick_t pause_date;
+ /* Date of the last input PLAYING event, to detect ES PAUSED events
+ * delivered after their pause was resumed */
+ vlc_tick_t last_resume_date;
bool stopping;
struct vlc_player_timer_source sources[VLC_PLAYER_TIMER_TYPE_COUNT];
=====================================
src/player/timer.c
=====================================
@@ -42,6 +42,7 @@ vlc_player_ResetTimer(vlc_player_t *player)
player->timer.seek_position = -1;
player->timer.update_state = UPDATE_STATE_RESUMED;
player->timer.pause_date = VLC_TICK_INVALID;
+ player->timer.last_resume_date = VLC_TICK_INVALID;
player->timer.stopping = false;
vlc_mutex_unlock(&player->timer.lock);
@@ -262,8 +263,17 @@ vlc_player_UpdateTimerEvent(vlc_player_t *player, vlc_es_id_t *es_source,
case VLC_PLAYER_TIMER_EVENT_PAUSED:
assert(system_date != VLC_TICK_INVALID);
- player->timer.update_state = UPDATE_STATE_PAUSED;
- player->timer.pause_date = system_date;
+
+ /* An ES PAUSED event can be delivered after its pause was
+ * resumed. It is still reported: per-ES events are delivered
+ * in order, but it should not touch player timer state. */
+ if (es_source == NULL
+ || player->timer.last_resume_date == VLC_TICK_INVALID
+ || system_date >= player->timer.last_resume_date)
+ {
+ player->timer.update_state = UPDATE_STATE_PAUSED;
+ player->timer.pause_date = system_date;
+ }
for (size_t i = 0; i < VLC_PLAYER_TIMER_TYPE_COUNT; ++i)
{
@@ -271,11 +281,11 @@ vlc_player_UpdateTimerEvent(vlc_player_t *player, vlc_es_id_t *es_source,
if (source->es != es_source)
continue;
- /* The input might signal paused clock and then output
- * would signal it. This flag filters this case here. */
- if (source->pause_reported)
+ /* The input and the output signal the same pause with the
+ * same date */
+ if (source->reported_pause_date == system_date)
continue;
- source->pause_reported = true;
+ source->reported_pause_date = system_date;
vlc_player_SendTimerPause(player, source, system_date,
i == VLC_PLAYER_TIMER_TYPE_SMPTE);
}
@@ -284,9 +294,9 @@ vlc_player_UpdateTimerEvent(vlc_player_t *player, vlc_es_id_t *es_source,
case VLC_PLAYER_TIMER_EVENT_PLAYING:
assert(!player->timer.stopping);
+ if (system_date != VLC_TICK_INVALID)
+ player->timer.last_resume_date = system_date;
player->timer.update_state = UPDATE_STATE_RESUMING;
- for (size_t i = 0; i < VLC_PLAYER_TIMER_TYPE_COUNT; ++i)
- player->timer.sources[i].pause_reported = false;
break;
case VLC_PLAYER_TIMER_EVENT_STOPPING:
@@ -763,7 +773,7 @@ vlc_player_InitTimer(vlc_player_t *player)
player->timer.sources[i].point.system_date = VLC_TICK_INVALID;
player->timer.sources[i].es = NULL;
player->timer.sources[i].seeking = false;
- player->timer.sources[i].pause_reported = false;
+ player->timer.sources[i].reported_pause_date = VLC_TICK_INVALID;
}
vlc_player_ResetTimer(player);
}
=====================================
test/src/player/pause.c
=====================================
@@ -85,9 +85,13 @@ test_pause(struct ctx *ctx)
wait_state(ctx, VLC_PLAYER_STATE_PAUSED);
- /* Ensure all timers are paused */
- wait_timer_report(player, &video_timer, REPORT_TIMER_PAUSED);
- wait_timer_report(player, &timer, REPORT_TIMER_PAUSED);
+ /* Ensure all timers are paused, on the second pause (and not on a stale
+ * report from the first one) */
+ struct report_timer video_paused =
+ wait_timer_report(player, &video_timer, REPORT_TIMER_PAUSED);
+ struct report_timer regular_paused =
+ wait_timer_report(player, &timer, REPORT_TIMER_PAUSED);
+ assert(video_paused.paused_date == regular_paused.paused_date);
/* Ensure we stay paused */
vlc_tick_sleep(VLC_TICK_FROM_MS(100));
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ca7612ed6a340d17b842ebcf51bc8dd81b307288...0567f08aaf0a5f430a82cdcca63e9e57666b880c
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ca7612ed6a340d17b842ebcf51bc8dd81b307288...0567f08aaf0a5f430a82cdcca63e9e57666b880c
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help
More information about the vlc-commits
mailing list