fix(video): recover the axis when a picture is not a whole number of ticks long (#409) - #427
Merged
Merged
Conversation
#409's repair reads a rank out of the bitstream and puts it back on the ladder the container wrote, and it needed that ladder to advance by one constant. A constant frame rate does not always produce one: at a 1200000 timescale the retest asset's pictures are 200202/5 ticks apart, so its sample table can only alternate between 40040 and 40041, and the classifier fell closed on a ladder it read as variable frame timing. The file stayed exactly as broken as it was reported. A two-valued ladder is now read as the quantization it is. The cycle it repeats names the fraction, and a cycle counts only when it has been seen through twice. The pattern it rounds to names the phase of the lattice it was quantized from, which is the one thing a whole-tick ladder cannot carry and this one can: the reporting asset sits on phase 2 while its reorder delay is 1, so the phase is not implied by anything else and has to be read. Ranks are then placed on that lattice instead of on a step, which reproduces the muxer exactly rather than a tick beside it, and the whole-tick ladder stays the special case it always was. Reading the phase also makes the verdict independent of where the sample was taken: a session that starts inside the file now describes the same axis as one that starts at byte 0. Measured before the change, a sample taken after a seek classified the same file as unrepairable. What does not change: how far the ladder runs ahead of presentation still comes from the container header, because every alignment fits the ladder equally well and only the header can decide; the container index is still folded by one constant, so an index entry can never disagree with the packet it points at; and a picture the lattice cannot place falls back to the rounded step rather than being handed on in decode order. Variable frame timing, a ladder with a dropped picture, and a wobble that never repeats are all still left untouched. Verified against a fractional twin pair built the way @orut34iop built the first one (33 packets, three coded video sequences, both writer shapes, from the head and after a seek): every repaired packet carries the healthy twin's PTS and DTS exactly. Full suite 2091 tests green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RbWZLwBVLGM1xUVXa9NeJ1
The property that separates placing a rank on a lattice from requiring the ladder to sit on one: when a coded video sequence opens beside the lattice, the rounded step still describes the stream to within a tick and anchors on the container's own timestamp, so it cannot drift. Handing the picture on with its raw timestamps would be the defect returning mid-file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RbWZLwBVLGM1xUVXa9NeJ1
This was referenced Aug 25, 2026
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 this fixes
@orut34iop retested the released #413 + #415 repair on the original reporting asset and it still juddered from the first frame. The diagnosis in that retest is correct and this change is built on it: the asset is constant rate, but a picture is not a whole number of ticks long, so its sample table can only alternate between the two neighbouring counts (
200202/5ticks at a 1200000 timescale, cycling 40040/40041). The classifier demanded one identical step, read that as variable frame timing, and fell closed. Zero packets repaired.Reproduced here before touching anything, on a fixture pair built the same way the first pair was: the engine passes the whole file through with
PTS == DTS, every picture still in decode order.The change
A two-valued ladder is read as the quantization it is.
anchor + index * step, so the repair reproduces what the muxer would have written instead of landing a tick beside it. A whole-tick ladder takes the same path it always did, byte for byte.Reading the phase has a second effect worth naming: the verdict no longer depends on where the sample was taken. Measured before the change, sampling the same file after a seek classified it as unrepairable; now a session that starts inside the file describes the same axis as one that starts at byte 0.
What deliberately does not change
presentationShiftalready answers it fromstart_timewith a clamp that bounds the damage to one reorder head. The lattice work only requires that the answer resolve to a whole number of pictures.Verification
A fractional twin pair, built the way @orut34iop built the first one: one encode at
1000000/33367fps in a 1200000 timescale muxed twice, the composition offsets stream-copied away from the second. 33 packets, three coded video sequences, both writer shapes (edit list retained and lifted to non-negative timestamps).swift test: 2091 tests in 296 suites, green, run against a checkout withFixtures/present so the file-backed suites actually execute.Closes nothing on its own: #409 stays open for @orut34iop's retest on the original asset.