Repository navigation
fix(subtitles): a zero offset reach stops the forward prefetch's second download (#1015) - #1017
Conversation
…nd download (#1015) Selecting an embedded subtitle on a remote source started the #151 forward prefetch, a subtitle-only side reader that downloads the interleaved video a second time. Its cues beyond the pump's forward park only serve an advance offset or the OCR worker, so it now runs only when something reads ahead: maximumSubtitleOffsetSeconds above 0, a negative softwareSubtitleDelaySeconds, or an armed OCR worker. Either change starts or stops it mid-session, under the new noAdvanceReach stop reason. The default reach (60) keeps today's behaviour. Measured with aetherctl over HTTP, 40 s of a 720p 6 Mbit/s MKV with an embedded SRT, two runs each: 92.9 / 92.4 MB with the default reach, 53.8 / 54.1 MB with reach 0, 53.4 MB with subtitles off. Every cue from 30 to 69 s arrived in both arms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz
There was a problem hiding this comment.
Automated review
Status: 🟡 Minor follow-ups. Only small touch-ups left.
The PR gates the #151 forward subtitle prefetch on an actual need: a host offset reach above 0, a negative softwareSubtitleDelaySeconds, or an armed OCR worker. Changing the reach or the delay starts or stops the prefetch mid-session. The fix is in the engine, it removes the duplicate download at its cause, and the default (60) keeps today's behaviour, so the direction is right.
I checked every path that starts the prefetch: selection (startAt), drain-tick re-anchor, OCR arm and disarm through syncSubtitleOCRWithNativeSelection, and the new reach and delay setters. Each ends up at the new guard or at the shared shouldRunSubtitleForwardPrefetch. Disarming OCR at reach 0 changes the lead, so it skips the in-place re-anchor and stops under .noAdvanceReach as intended. The sign in subtitleAdvanceReach matches the compositor (subtitleTime = seconds - delaySeconds), so only a negative delay reads ahead.
Findings
- Nit: the new test file is named after the issue, which
CONTRIBUTING.mdasks to avoid. These cases fit in the existing forward-prefetch or offset-reach test files (Tests/AetherEngineTests/Issue1015PrefetchAdvanceReachTests.swift:153). - Nit: in
docs/formats.mdthe new paragraph separates the #151 paragraph from its bullet list (docs/formats.md:983).
Checklist: CHANGELOG yes, docs yes, tests yes, traits both ways n.a.
Needs a device run: a device run with reach 0 on a remote MKV over the native route, a bitmap (PGS) track and the software host, to confirm that the pump's harvest alone delivers cues on time after seeks.
Thanks for the measured byte counts and the careful gating.
Line comments
Tests/AetherEngineTests/Issue1015PrefetchAdvanceReachTests.swift:153: Nit:CONTRIBUTING.mdasks that a test file be named after the behaviour, not the issue, with the issue number in the test name. These cases fit inIssue151SubtitleForwardPrefetchTests.swift, which this PR already touches, or inIssue929OffsetReachTests.swift. Adding them there, withAE#1015in each@Testname, avoids yet anotherIssue<N>file.docs/formats.md:983: Nit: this paragraph now sits between the #151 paragraph and the bullet list that describes it. A reader can then take bullets like "SosubtitleCuesholds cues ahead of the playhead..." as following from the gating rule. Moving the paragraph below the list, or turning it into a bullet such as "Runs only when ...", keeps the list attached to the paragraph it explains.
Automated review by Quint (Claude) of 015e606. It reads the code, it does not build or run it; a maintainer reviews and merges.
…ts, keep the docs list attached Quint's review on #1017: CONTRIBUTING.md names test files after behaviour, not issues, so the advance-reach cases move into Issue151SubtitleForwardPrefetchTests.swift with AE#1015 in each test name. The new gating paragraph in formats.md becomes a bullet of the #151 list instead of splitting the paragraph from the list that explains it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz
There was a problem hiding this comment.
Automated review
Status: 🟢 Clean. Nothing left to fix, ready for a maintainer.
I checked the new head (9849fbb). Both nits from the last review are fixed, and the gating logic is the same as before.
- Fixed: the AE#1015 cases are now in
Issue151SubtitleForwardPrefetchTests.swiftasSubtitleForwardPrefetchAdvanceReachTests, withAE#1015in each@Testname. - Fixed: the
docs/formats.mdparagraph is now a bullet under the #151 list, so the list stays with the paragraph it explains.
Findings
No open findings.
Checklist: CHANGELOG yes, docs yes, tests yes, traits both ways n.a.
Needs a device run: set the reach to 0 and check that the pump's harvest alone delivers cues on time after seeks. Cover a remote MKV on the native route, a bitmap (PGS) track and the software host.
Thanks for the quick follow-up.
Automated review by Quint (Claude) of 9849fbb. It reads the code, it does not build or run it; a maintainer reviews and merges.
Addresses #1015.
What changes
maximumSubtitleOffsetSeconds = 0now also stops the #151 forward subtitle prefetch, for text and bitmap tracks. That reader downloads an interleaved MKV or MP4 a second time, and its cues beyond the pump's forward park only serve an advance offset.The prefetch still runs when something reads ahead:
maximumSubtitleOffsetSecondsabove 0 (the default, 60, so nothing changes for hosts that set nothing)softwareSubtitleDelaySecondsChanging the reach or the software delay starts or stops it mid-session. A stop logs
reason=noAdvanceReach.No new API: the reporter's proposed
.whenAdvancingis what a zero reach plus a negative software delay already does. A shorter lead would not save bytes, the reader is sequential.Measurement
aetherctl play --subs srt --start-position 30 --seconds 40over a threaded range server, 720p 6 Mbit/s MKV with one embedded SRT, bytes counted at the origin:Every cue from 30 to 69 s arrived in both arms; with reach 0 the pump's harvest still reached 116 s.
Tests
Issue1015PrefetchAdvanceReachTests(gating, delay sign, mid-session stop and start, no start without a drain target). Full suite green: XCTest 836, swift-testing 5819.🤖 Generated with Claude Code
https://claude.ai/code/session_01SeT6NgMt1vv32kPBhUmsUz