Skip to content

pi3-64: reduced-seam in-slot video looping (SEGMENT seeks) - #3174

Merged
vpetersson merged 3 commits into
masterfrom
pi3-64-gapless-loop
Jul 9, 2026
Merged

pi3-64: reduced-seam in-slot video looping (SEGMENT seeks)#3174
vpetersson merged 3 commits into
masterfrom
pi3-64-gapless-loop

Conversation

@vpetersson

@vpetersson vpetersson commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What

Reduces the loop-point frame drop for in-slot video looping on pi3-64. When a clip is shorter than its playlist slot, the viewer loops it in-process; the previous flushing-seek restart fully re-primed the bcm2835 HW decoder at each internal loop, dropping ~0.2 s of frames. This switches the overlay video (and separate audio) pipeline to SEGMENT playback so the decoder is not fully torn down at the loop point.

Follow-up to #3164 (merged).

How

  • After preroll, an initial flushing segment seek enters segment mode; each SEGMENT_DONE re-arms the segment without flushing.
  • The initial segment seek is issued from GST_MESSAGE_ASYNC_DONE (preroll complete), not synchronously after set_state(PLAYING) — a seek issued while the pipeline is still prerolling returns FALSE, so segment mode would never engage.
  • gstSegmentSeek returns the seek result; the SEGMENT_DONE handlers fall back to the flushing restart if a re-arm fails (in segment mode no EOS is posted, so a failed re-arm would otherwise freeze the clip forever).
  • EOS handling is retained as a fallback for pipelines that don't deliver SEGMENT_DONE.

Validation on real pi3-64 (192.168.x hardware, 1080p30 H.264, 60 s clip looping in a 300 s slot)

Measured loop-point frame drop (SAMPLE expected − rendered in the loop-transition second), steady-state background drop ≈ 0.09 frames/s:

Build Segment mode engaged? Loop-point drop
master (flushing restart) n/a ~6–10 frames (~0.2 s)
this PR, first two commits only No — init seek raced preroll, silently fell back to EOS/flush ~6–10 frames (no change)
+ ASYNC_DONE fix (3rd commit) YesSEGMENT_DONE every loop, video + audio ~1–5 frames (~0.1 s)

Honest framing: this roughly halves the loop hitch; it does not make looping perfectly gapless. The bcm2835 v4l2 decoder still partially re-primes even on a non-flushing segment seek. Comments/wording were changed from "gapless" to "reduced-seam" to match. True gaplessness on this decoder would likely need a non-seek approach.

Scope

Only affects looping within a slot. A single-video playlist still rebuilds at each slot boundary — a separate scheduler change.

Commits

  1. Original SEGMENT-seek change (did not engage on hardware on its own).
  2. Fall back to flushing loop if a segment re-arm seek fails (prevents a freeze-forever stall; from Copilot review).
  3. Enter segment mode on ASYNC_DONE — the fix that actually makes segment mode engage on pi3-64.

🤖 Generated with Claude Code

When a video is shorter than its playlist slot, the viewer loops it
in-process. The previous flushing-seek restart re-primed the bcm2835 HW
decoder at each internal loop, dropping ~0.35s of frames per iteration.

Switch the overlay video pipeline (and the separate audio pipeline) to
SEGMENT playback: an initial flushing segment seek enters segment mode,
then each SEGMENT_DONE re-arms the segment WITHOUT flushing, so the
decoder is never torn down and the loop is gapless. EOS handling is kept
as a fallback for pipelines that don't deliver SEGMENT_DONE.

Note: this only affects looping WITHIN a slot. A single-video playlist
still rebuilds at each slot boundary (the scheduler shows each asset for
its duration then re-shows) — eliminating that is a separate, cross-board
scheduler change.

Stacked on the pi3-64 HW video PR (gstPlayOverlay / gstStartAudio).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@vpetersson
vpetersson force-pushed the pi3-64-gapless-loop branch from 7d9a63c to 221984a Compare July 9, 2026 13:32
@vpetersson
vpetersson changed the base branch from worktree-deep-coalescing-moon to master July 9, 2026 13:33
@vpetersson
vpetersson requested a review from Copilot July 9, 2026 16:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the pi3-64 GStreamer overlay playback path to achieve gapless in-slot clip looping by switching from flushing seek restarts to SEGMENT seek playback, re-arming segments on SEGMENT_DONE without tearing down the bcm2835 HW decoder. It also applies the same segment-loop approach to the separate audio pipeline to keep audio looping gaplessly and aligned to the video loop point.

Changes:

  • Handle GST_MESSAGE_SEGMENT_DONE on both the video and audio pipeline bus watches.
  • Introduce gstSegmentSeek() and *SegmentDone() helpers to implement non-flushing segment re-arming for looping.
  • Enter segment mode after starting playback for both overlay video and audio pipelines.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/anthias_webview/src/videoview.h Declares new segment-seek and segment-done helper methods for gapless looping.
src/anthias_webview/src/videoview.cpp Implements segment seek looping, wires SEGMENT_DONE bus handling, and enables segment mode on playback start (video overlay + audio).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/anthias_webview/src/videoview.cpp Outdated
In segment mode the pipeline posts SEGMENT_DONE, never EOS, so a
non-flushing re-arm seek that fails at the loop point would freeze the
clip on its last frame forever (no EOS to trigger the fallback path).

Make gstSegmentSeek return the gst_element_seek result and have the
*SegmentDone handlers fall back to the flushing restart
(gstRestartLoop / gstLoopAudio) when a re-arm fails, so the clip keeps
looping (with a small seam) instead of stalling. Also add
GST_SEEK_FLAG_KEY_UNIT for consistency with the existing flushing loop
seeks (target 0 is always a keyframe, so behaviour is unchanged).

Addresses Copilot review feedback on the gapless-loop change.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread src/anthias_webview/src/videoview.cpp Outdated
Comment on lines +1499 to +1500
// Match the video: segment playback so audio loops gaplessly too.
gstSegmentSeek(gstAudioPipeline, true);
The initial segment seek was issued synchronously right after
set_state(PLAYING), while the pipeline was still async-prerolling, so
gst_element_seek returned FALSE and the pipeline never entered segment
mode. Looping then fell back to the flushing EOS restart — verified on a
real pi3-64: the clip dropped the same ~6 frames (~0.2s) at each loop as
before this whole change, i.e. the gapless path never engaged.

Enter segment mode from GST_MESSAGE_ASYNC_DONE (preroll complete) for
both the overlay video and audio pipelines, guarded by
gstSegmentArmed / gstAudioSegmentArmed so the extra ASYNC_DONE the
flushing seek itself posts doesn't re-arm. Arming latches only on a
successful seek, so an early ASYNC_DONE from a child bin just retries on
the pipeline's own ASYNC_DONE.

With segment mode actually engaged, every loop now posts SEGMENT_DONE
(video + audio) instead of EOS, and the loop-point drop falls to ~1-3
frames (~0.1s). Note: this is reduced, not eliminated — the bcm2835
v4l2 decoder still partially re-primes even on a non-flushing segment
seek. Comments reworded from "gapless" to "reduced-seam" to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@vpetersson vpetersson changed the title pi3-64 gapless clip looping (SEGMENT seeks) pi3-64: reduced-seam in-slot video looping (SEGMENT seeks) Jul 9, 2026
@vpetersson
vpetersson requested a review from Copilot July 9, 2026 17:51
@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comment on lines +1706 to +1709
if (!gstSegmentSeek(gstPipeline, false)) {
gstRestartLoop();
return;
}
Comment on lines +1712 to +1714
if (!gstSegmentSeek(gstAudioPipeline, false)) {
gstLoopAudio();
}
Comment on lines +1723 to +1725
if (!gstSegmentSeek(gstAudioPipeline, false)) {
gstLoopAudio();
}
@vpetersson
vpetersson merged commit 5e5719c into master Jul 9, 2026
8 checks passed
@vpetersson
vpetersson deleted the pi3-64-gapless-loop branch July 9, 2026 18:14
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.

2 participants