feat: short-circuit MIME detection for legacy QuickTime pnot files#59
Merged
Conversation
added 2 commits
June 9, 2026 02:17
Files from early consumer cameras (Nikon COOLPIX S5/P5000, Casio EX-Z50,
Fujifilm FinePix older AVI/MOV mixes, etc., ca. 2003-2008) start with a
`pnot` (preview) atom instead of `ftyp`. Such files were rejected by
`parse_bmff_mime` with `Error::UnsupportedFormat`, even though their
`moov > mvhd` structure is fully standard QuickTime and the downstream
`mov.rs::extract_moov_body_from_buf` (which scans atoms in order and
skips unrecognized ones) can extract `creation_time` without changes.
Root cause:
1. `get_ftyp_and_major_brand` only accepts `ftyp` or `wide` as the
first box and returns `Malformed` otherwise — caught and mapped to
`UnsupportedFormat` by `parse_bmff_mime`.
2. The `wide` path falls through to a `travel_header(... != "mdat")`
scan. Even adding a `pnot` arm there would not help: the
`HEADER_PARSE_BUF_SIZE` is 128 bytes, while a real-world `moov`
atom typically pushes `mdat` well past byte 128, so the scan
returns `Incomplete` and we fall into `UnsupportedFormat`.
Fix:
Short-circuit MIME detection: if the first box is `pnot`, the file is
QuickTime — no need to scan further. The atom is a QuickTime-specific
preview structure and unambiguously identifies the container.
Verified against three NIKON DIGITAL CAMERA / S5 MOV files captured in
2006-2007: before the patch `populate_video_dates` returned no
`TrackInfoTag::CreateDate`; after the patch the value matches what
ExifTool reads (`[QuickTime] CreateDate`).
No new dependencies. No behaviour change for `ftyp`/`wide`-prefixed
files. Performance impact: one extra BoxHolder::parse on every call
into parse_bmff_mime, which is cheap (single box header parse over
the existing buffer).
Some legacy QuickTime MOV files (e.g. early consumer cameras) start directly with a huge `mdat` atom — no `ftyp`/`wide`/`pnot` header at all, with `moov` at the end of the file. `get_ftyp_and_major_brand` rejects such files as malformed, and the generic mdat fallback scan cannot help because the 128-byte header parse buffer ends long before the mdat body does. Extend the existing pnot short-circuit to also accept a leading mdat, and switch it to header-only parsing (`BoxHeader::parse`): the previous `BoxHolder::parse` requires the full box body in the buffer, which a multi-megabyte leading mdat can never satisfy, so the short-circuit silently fell through. `extract_moov_body_from_buf` already skips arbitrarily large mdat bodies via `ClearAndSkip`, so track parsing works unchanged. Verified against a real-world mdat-first MOV (moov at EOF, 2.8 MB mdat): CreateDate matches ExifTool output.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #59 +/- ##
==========================================
+ Coverage 90.50% 90.52% +0.02%
==========================================
Files 38 38
Lines 8570 8593 +23
==========================================
+ Hits 7756 7779 +23
Misses 814 814
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Owner
|
Thanks for the fix! This is a clean and well-explained change. |
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.
Files from early consumer cameras (Nikon COOLPIX S5/P5000, Casio EX-Z50, Fujifilm FinePix older AVI/MOV mixes, etc., ca. 2003-2008) start with a
pnot(preview) atom instead offtyp. Such files were rejected byparse_bmff_mimewithError::UnsupportedFormat, even though theirmoov > mvhdstructure is fully standard QuickTime and the downstreammov.rs::extract_moov_body_from_buf(which scans atoms in order and skips unrecognized ones) can extractcreation_timewithout changes.Root cause:
get_ftyp_and_major_brandonly acceptsftyporwideas the first box and returnsMalformedotherwise — caught and mapped toUnsupportedFormatbyparse_bmff_mime.The
widepath falls through to atravel_header(... != "mdat")scan. Even adding apnotarm there would not help: theHEADER_PARSE_BUF_SIZEis 128 bytes, while a real-worldmoovatom typically pushesmdatwell past byte 128, so the scan returnsIncompleteand we fall intoUnsupportedFormat.Fix:
Short-circuit MIME detection: if the first box is
pnot, the file is QuickTime — no need to scan further. The atom is a QuickTime-specific preview structure and unambiguously identifies the container.Verified against three NIKON DIGITAL CAMERA / S5 MOV files captured in 2006-2007: before the patch
populate_video_datesreturned noTrackInfoTag::CreateDate; after the patch the value matches what ExifTool reads ([QuickTime] CreateDate).No new dependencies. No behaviour change for
ftyp/wide-prefixed files. Performance impact: one extra BoxHolder::parse on every call into parse_bmff_mime, which is cheap (single box header parse over the existing buffer).