Skip to content

Wait for a seek from the end to take effect before playing - #78

Merged
danielchalmers merged 1 commit into
mainfrom
claude/replay-from-finished-clip
Sep 17, 2026
Merged

danielchalmers merged 1 commit into
mainfrom
claude/replay-from-finished-clip

Conversation

@danielchalmers

Copy link
Copy Markdown
Owner

Pressing play on a clip that has finished often left the video frozen on its first frame while the transport showed "playing". Seeking back from the end and then pressing play froze almost every time. This predates v1.0.0.

Cause

From FlyleafLib's own source (Player.Playback.cs, v3.11.5):

  • Play() returns without doing anything while status == Status.Ended (line 37).
  • A seek issued from Ended only flips the status back to Paused later, from the background task that performs the seek (lines 256–260).

PlayAsync handles a finished clip by seeking to the start and playing back to back. So Play() usually lands before that task has run, gets dropped, and the controller reports playback that never started.

Fix

FlyleafCameraPlayer.SeekAsync notes whether the player was Ended when the seek was issued, and if so waits for the status to leave Ended before returning. Player.Status reads the live field rather than a dispatcher-updated copy, so the flip is visible the moment it happens and the wait is normally a few milliseconds. A 1s cap keeps a seek that never runs from stalling the caller. Seeks from any other state return immediately, as before.

Measured

Real stack, FlyleafLib 3.11.5, 30 iterations each. Every check requires the player's own clock to advance, because a clip frozen at zero also reports IsPlaying and a small Position.

scenario before after
play after the clip finishes 16/30 30/30
seek back from the end, then play 0/30 30/30
seek just before the end, play immediately 15/30 30/30
play from just before the end 30/30 30/30

With FlyleafLib 3.10.4, the library v1.0.0 shipped, the first two froze 8/20 and 16/20. This isn't a regression from the recent upgrades.

The integration harness passes 140/140 with the fix: install, playback, six-camera sync, unreadable chunks, file handles, export and color. Its replay check now requires real movement; the old version passed on a clip frozen at zero, which is how this went unnoticed.

This is Flyleaf behavior that the unit-suite fakes don't model, so there's no unit test. 374 tests green, dotnet format --verify-no-changes clean.

How to verify by hand

Open any clip, let it play to the end (or scrub to the end), then press Space. The video should play from the start. Before this change it often stayed on the first frame while the play button showed pause.

Pressing play on a clip that has finished often left the video frozen on its first frame while the transport reported playback.
Seeking back from the end and pressing play was worse, and froze almost every time.

Flyleaf's Play() returns without doing anything while the player's status is Ended.
A seek issued from Ended only moves the status back to Paused later, from the background task that performs the seek.
PlayAsync handles a finished clip by seeking to the start and playing back to back, so Play() usually lands before that task has run, is dropped, and the controller then reports playback that never started.

FlyleafCameraPlayer.SeekAsync now notes whether the player was Ended when the seek was issued, and if so waits for the status to leave Ended before returning.
Player.Status reads the live field rather than a dispatcher-updated copy, so the flip is visible the moment the seek task makes it, and the wait is normally a few milliseconds.
A 1s cap keeps a seek that never runs from stalling the caller.
Seeks from any other state return immediately, exactly as before.

Measured on the real stack with FlyleafLib 3.11.5, 30 iterations each, requiring the player's own clock to advance rather than trusting IsPlaying:

  play after the clip finishes                 16/30 before   30/30 after
  seek back from the end, then play             0/30 before   30/30 after
  seek just before the end, play immediately   15/30 before   30/30 after
  play from just before the end                30/30 before   30/30 after

The bug predates this change and the Flyleaf upgrades: with the FlyleafLib 3.10.4 that shipped in v1.0.0, the first two froze 8 of 20 and 16 of 20.
The integration harness passes 140/140 with the fix, including a replay check that now requires movement, since the old one passed on a clip frozen at zero.

This is Flyleaf behavior, which the fakes in the unit suite do not model, so it has no unit test.
374 tests green.
@danielchalmers
danielchalmers merged commit 0c288b9 into main Sep 17, 2026
1 check passed
@danielchalmers
danielchalmers deleted the claude/replay-from-finished-clip branch September 17, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant