Split out of AE#408, where it was found while measuring the fix at the serving layer.
What happens
Video packets are routed into segments by the keyframe-gated cutter (VODSegmentCutter.index, #92): a segment opens at the IRAP that reaches its plan boundary, so a boundary no IRAP reaches is stepped over. Audio packets are routed by segmentIndex(forSourcePts:), which is a plain boundary lookup with no such gate.
Where every boundary has an IRAP the two agree and nothing shows. Where they do not, the audio still crosses the boundary, ensureMuxer(forSegmentIndex:) cuts there and opens the folded index, and the video packets that follow land in a segment whose first video sample is not a sync sample.
Measured on a fixture built with Scripts/mkv-cue-fixture.py (cue points at non-sync positions, a deliberate 12 s keyframe drought at 43 s), fetched from the loopback server and read back as init.mp4 + segN:
| segment |
advertised |
first video packet |
sync samples inside |
| seg10 |
40.0-44.0 |
38.417000,K__ |
38.417 |
| seg11 |
44.0-48.0 |
44.000000,___ |
none |
| seg12 |
48.0-52.0 |
48.042000,___ |
none |
| seg13 |
52.0-56.0 |
52.000000,___ |
55.000 |
The cuts sit exactly on the plan boundaries, which is the audio crossing them; the #65 ledger lines for the same run show the video cutter folding 10 straight to 13.
What it costs today
Less than it looks, on this client:
- A consumer that arrives sequentially is already decoding, so a mid-GOP segment costs it nothing.
- A cold arrival on a folded index (a seek) takes the out-of-range path, which restarts the producer there. Since AE#408 that restart opens on a sync sample, so what it gets back is decodable and covers its advertised start.
- A cold arrival on an index that is already cached from a sequential pass gets the mid-GOP segment, and AVPlayer resolves it by fetching the PREVIOUS segment first:
GET /seg10.mp4 immediately after seek#2 programmatic began target=46.00, then landed rendered=46.00 target=46.00.
So the visible cost is one extra segment fetch on that last path. Not free: on the AE#408 reporting asset the segments run about 17 MB.
The playlist does not carry EXT-X-INDEPENDENT-SEGMENTS, so nothing in the manifest claims otherwise. Measured on macOS only; a tvOS reading is worth having before deciding this is benign, since the backward walk is the client's choice, not a guarantee.
Direction
The producer knows, at adopt time, whether the first video sample it routed into a segment was a sync sample. Recording that with the cache entry would let a COLD arrival treat a non-decodable cached segment the way the #358 fold path already treats a missing one, and re-produce it with a restart at that index. Sequential arrivals keep what they have, since it costs them nothing.
Not proposing to let the video fold win over audio: that would leave the folded indices with no media at all, which turns a benign extra fetch into a hole.
Split out of AE#408, where it was found while measuring the fix at the serving layer.
What happens
Video packets are routed into segments by the keyframe-gated cutter (
VODSegmentCutter.index, #92): a segment opens at the IRAP that reaches its plan boundary, so a boundary no IRAP reaches is stepped over. Audio packets are routed bysegmentIndex(forSourcePts:), which is a plain boundary lookup with no such gate.Where every boundary has an IRAP the two agree and nothing shows. Where they do not, the audio still crosses the boundary,
ensureMuxer(forSegmentIndex:)cuts there and opens the folded index, and the video packets that follow land in a segment whose first video sample is not a sync sample.Measured on a fixture built with
Scripts/mkv-cue-fixture.py(cue points at non-sync positions, a deliberate 12 s keyframe drought at 43 s), fetched from the loopback server and read back asinit.mp4 + segN:38.417000,K__44.000000,___48.042000,___52.000000,___The cuts sit exactly on the plan boundaries, which is the audio crossing them; the
#65 ledgerlines for the same run show the video cutter folding 10 straight to 13.What it costs today
Less than it looks, on this client:
GET /seg10.mp4immediately afterseek#2 programmatic began target=46.00, thenlanded rendered=46.00 target=46.00.So the visible cost is one extra segment fetch on that last path. Not free: on the AE#408 reporting asset the segments run about 17 MB.
The playlist does not carry
EXT-X-INDEPENDENT-SEGMENTS, so nothing in the manifest claims otherwise. Measured on macOS only; a tvOS reading is worth having before deciding this is benign, since the backward walk is the client's choice, not a guarantee.Direction
The producer knows, at adopt time, whether the first video sample it routed into a segment was a sync sample. Recording that with the cache entry would let a COLD arrival treat a non-decodable cached segment the way the #358 fold path already treats a missing one, and re-produce it with a restart at that index. Sequential arrivals keep what they have, since it costs them nothing.
Not proposing to let the video fold win over audio: that would leave the folded indices with no media at all, which turns a benign extra fetch into a hole.