Ignore stco chunks with no samples to fill them - #455
Open
kinetiknz wants to merge 2 commits into
Open
Conversation
Some files declare more chunks in 'stco' than the samples in 'stsz' can fill, and the surplus chunk offsets are bogus. Treat 'stsz' as authoritative for the sample count and stop once every sample is placed, rather than rejecting the track. Matches ffmpeg's mov_build_index(). Fixes bug 2026607.
Collaborator
Author
|
@alastor0325 Would you mind reviewing this please? |
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.
Fixes bug 2026607, where videos on etoland.co.kr fail in Firefox but play in Chrome and Safari.
The file
The reported MP4 has one video track with an inconsistent sample table:
stszsample_size=0,sample_count=112, sizes summing to 529972stscfirst_chunk=1, samples_per_chunk=112stcoentry_count=2:0x90E(the mdat payload start) and0xC000009D(3GB past the 532290-byte file)The 112 sample sizes exactly fill the mdat, so the second chunk offset is garbage that no sample maps into.
The failure
mp4parse_newsucceeds;mp4parse_get_indice_tablereturnsInvalid.SampleToChunkIteratorextends the laststscentry across every chunkstcodeclares, yielding 2 × 112 = 224 samples. At sample 113 thestszsize iterator is exhausted,end_offsetfalls through to 0, andcreate_sample_tablereturnsNone, rejecting the whole track. Gecko surfaces that asNS_ERROR_DOM_MEDIA_METADATA_ERR.The fix
Treat
stszas authoritative for the sample count and stop once every sample is placed. This is what ffmpeg'smov_build_index()does — it iterates chunks driven bystcojust like we do, but bounds the inner loop by thestszsample count and keeps the entries already built:sc->sample_countis assigned inmov_read_stszbefore theif (sample_size) return 0;early-out, so it bounds both the size-table and constant-sample-size cases.SampleSizeBoxnow retainssample_countfor the same reason: it was previously read and discarded whensample_size != 0.This also fixes a quieter variant. With a constant sample size there is no size table to run out of, so the surplus chunk produced a phantom sample at the bogus offset instead of an error — confirmed on a synthetic file, where the old code emitted a second indice ending at 3221226371.
ffmpeg comparison
nb_read_framesfor ffmpeg, indice-table result for mp4parse:wrong sample countstcowrong sample countstcowrong sample countchunk_out_of_range.mp4stscmid-table overshootWe diverged from ffmpeg in four rows before; we now match in all ten.
What stays strict
Tables inconsistent in the other direction —
stscnaming a chunkstcodoesn't have — remain an error. ffmpeg draws the same line insanity_checks(), and deliberately distinguishes the two failures:stsc_data[stsc_count - 1].first > chunk_countreturns 2 and fails the whole header (cases D and F); a chunk-bearing track with no samples returns 1 and is kept as an empty track (case G).The second commit documents this on
test_chunk_out_of_range.rs. That test arrived in 7563263 as a regression test against indexingstcoout of bounds, which used to panic before it was changed to useget()— theInvalidassertion was just what not panicking happened to produce, so it was worth recording that the strictness is now deliberate. That file's only defect is a single flipped bit:first_chunkis 16777217 (0x0100_0001) rather than 1. Repairing that bit makes it decode 17 frames everywhere (row D0).Behaviour change beyond the reported case
Row G: a track with
stsz sample_count=0but a non-emptystconow yields an empty sample table instead ofInvalid. This moves us toward ffmpeg, and Gecko already receives empty indice tables from fragmented init segments, so the shape is not new.Testing
New fixture
stco_extra_chunk.mp4(1670 bytes), derived from the existingvideo_colr_nclx_hdr10.mp4by adding one bogusstcoentry — it has the same single-chunkstsc/stszshape as the reported file. It returnsInvalidwithout the fix and the same 3-sample table as its unmodified parent with it.211 tests pass;
cargo fmt --checkandcargo clippy --all-targetsclean.🤖 Generated with Claude Code