pi3-64: reduced-seam in-slot video looping (SEGMENT seeks) - #3174
Merged
Conversation
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
force-pushed
the
pi3-64-gapless-loop
branch
from
July 9, 2026 13:32
7d9a63c to
221984a
Compare
There was a problem hiding this comment.
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_DONEon 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.
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]>
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]>
|
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(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



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
SEGMENT_DONEre-arms the segment without flushing.GST_MESSAGE_ASYNC_DONE(preroll complete), not synchronously afterset_state(PLAYING)— a seek issued while the pipeline is still prerolling returnsFALSE, so segment mode would never engage.gstSegmentSeekreturns the seek result; theSEGMENT_DONEhandlers 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).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 − renderedin the loop-transition second), steady-state background drop ≈ 0.09 frames/s:SEGMENT_DONEevery loop, video + audioHonest 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
ASYNC_DONE— the fix that actually makes segment mode engage on pi3-64.🤖 Generated with Claude Code