feat(stills): scrub stills on the software VOD path from the packet cache (AE#605) - #607
Merged
Merged
Conversation
…ache (AE#605) A VOD session the device cannot hardware-decode already spools its packets to a disk cache with keyframe cursors, and its seeks land in that cache, but scrubThumbnail had no arm for it and supportsCacheBackedStills was keyed on the native segment cache alone. On a source that refuses a second request (an IPTV account capped at one connection, a debrid link) the FrameExtractor fallback cannot open either, so every such session scrubbed blind. The still now comes out of that cache. SoftwarePacketDiskFIFO gains a history walk from a cursor on handles of its own, so the consumer's reader never moves; SoftwarePacketReadAhead plans the run (newest keyframe at or before the target, video only, through the target plus a reorder tail) under the cached seek's own eligibility rule; SoftwareStillExtractor replays the stored packets with their full envelope. It runs on the #544 still queue with the same newest-wins ticket and the same lazily built extractor. A target past what is retained answers nil rather than the frame before it. supportsCacheBackedStills is now true for a software VOD session reading a remote source and for a software live session, which already served stills but reported false. A local file keeps no cache and stays false. aetherctl play --sw --host-calls still gains a VOD arm. On a 300 s H.264 fixture over HTTP: before 0 of 3, after 2 of 3 (4.37 s shows 4, 24.37 s shows 24, in 53 and 41 ms, no network), and the aim 600 s past the frontier misses as it must. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014AVNwe8YDG9EQM7uHdjT3f
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.
Part of #605 (the first of its two gaps; the second is discussed on the issue).
What
A software VOD session already spools its packets to a disk cache with keyframe cursors, and its seeks land in that cache (#512/#519), but
scrubThumbnailhad no arm for it. On a source that refuses a second request, theFrameExtractorfallback cannot open either, so every VOD the device cannot hardware-decode scrubbed blind.SoftwarePacketDiskFIFO.readHistory(from:visit:): walks retained records from a cursor on handles of its own. The consumer's reader never moves. The lock covers only cursor validation and a tail snapshot, the generation is re-checked after the walk (a walk that raced a reset is refused), and a failure never poisons the store.SoftwarePacketReadAhead.stillRun(atSeconds:...): newest keyframe at or before the target, video packets only, through the target plus a reorder tail. It uses the cached seek's own eligibility rule, so a still is offered exactly where a commit would be a cache hit. There is no end clamp: a target past the frontier answers nil, not the frame before it.SoftwareStillExtractor.still(from: [SoftwareStoredPacket], ...): replays the stored packets with their full envelope (real dts, side data). It shares the Live on the software path has no scrub still: the preview is a SegmentCache feature, and the DVR packet ring it could decode from has no image consumer #544 still queue, newest-wins ticket and lazy extractor (The software live still extractor is built for every session, whether a still is ever asked for or not #595). VOD limits: 12 s span, 900 packets, reorder tail 16.supportsCacheBackedStills: now true for a software VOD session on a remote source and for a software live session (which served stills since Live on the software path has no scrub still: the preview is a SegmentCache feature, and the DVR packet ring it could decode from has no image consumer #544 but reported false). False for a local file, which keeps no cache.Verification
Issue605SoftwareVODStillTests): the history walk across chunks, early stop, stale and evicted cursors, run shape, consumer cursor untouched, refusal past the frontier, span bound, packet bound.swift test: 629 XCTest / 0 failures, 3356 swift-testing in 453 suites passed.aetherctl play --sw --host-calls still(new VOD arm) on a 300 s 720p H.264 testsrc fixture over a threaded HTTP range origin:supportsCacheBackedStills -> false, 0 of 3-> true, 2 of 3. 4.37 s decodes the frame showing4(mid-GOP, not snapped to the keyframe) in 53 ms, 24.37 s decodes24in 41 ms. The aim 600 s past the frontier misses as designed.rxstays flat (no network), and the drop counter matches the before arm.🤖 Generated with Claude Code
https://claude.ai/code/session_014AVNwe8YDG9EQM7uHdjT3f