Skip to content

Mp4: Update chunk offsets when creating udta/meta atoms - #688

Closed
jfietz wants to merge 1 commit into
Serial-ATA:mainfrom
jfietz:fix/mp4-create-udta-chunk-offsets
Closed

Mp4: Update chunk offsets when creating udta/meta atoms#688
jfietz wants to merge 1 commit into
Serial-ATA:mainfrom
jfietz:fix/mp4-create-udta-chunk-offsets

Conversation

@jfietz

@jfietz jfietz commented Aug 5, 2026

Copy link
Copy Markdown

Disclosure, per the note in CONTRIBUTING.md: I ran into this on my own media library and worked out the symptom myself, but I used AI for narrowing it down to these specific branches. PR and the tests were done with AI assistance, and I have reviewed and reproduced all of the results below. Happy to adjust the approach or trim the tests if you would prefer something smaller.


Fixes chunk offset handling when the tag container has to be created.

update_offsets was only reachable from save_to_existing. The two branches in
write_to that create the container - "No udta atom found, creating one" and
"No meta atom found, creating one" - spliced their bytes into moov without
touching stco/co64. For files where moov precedes mdat, that shifts the
media data while every chunk offset keeps pointing at the old location, leaving
the stream undecodable.

Both call sites now call update_offsets before the splice, while the offset
atoms are still at their pre-splice positions.

Adds three regression tests:

  • create_udta_updates_chunk_offsets and create_meta_updates_chunk_offsets,
    over minimal hand-built MP4s, one per creation path.
  • create_udta_updates_chunk_offsets_in_real_file, over a new
    faststart_no_udta.mp4 asset - a real H.264/AAC file that the current
    implementation corrupts. Generated from ffmpeg's synthetic testsrc/sine
    sources, so it carries no copyrighted content.

All three fail on main and pass with the fix. cargo test, cargo fmt and
cargo clippy are clean.

closes #686


Unrelated to this change, but noticed while running the checks in
CONTRIBUTING.md: cargo clippy --all-targets fails on current stable for
reasons that predate this branch. CI does not catch it, since it runs
cargo clippy --all-features without --all-targets and so never lints the
examples. #689 fixes that separately.

`update_offsets` was only called from `save_to_existing`. The two paths that
*create* the tag container - "No `udta` atom found, creating one" and "No
`meta` atom found, creating one" - spliced their bytes into `moov` without
updating `stco`/`co64`.

For files where `moov` precedes `mdat` (i.e. anything muxed with faststart),
this shifts the media data later in the file while every chunk offset keeps
pointing at the old location, so the media stream is no longer decodable.
Files with `mdat` before `moov` are unaffected, as are files that already
have a `udta`/`meta` pair, which is why this went unnoticed.

Both call sites now update the offsets before the splice, while the offset
atoms are still at their original positions.

Adds three regression tests: two over minimal synthetic MP4s covering both
creation paths, and one over `faststart_no_udta.mp4`, a real H.264/AAC file
that the current implementation corrupts. That asset was generated with
ffmpeg's `testsrc`/`sine` sources and contains no copyrighted material.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Serial-ATA Serial-ATA closed this Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mp4: Chunk offsets are not updated when the udta/meta atoms have to be created, corrupting faststart files

2 participants