Skip to content

Fix mdhd/mvhd version 1 (64-bit) atom parsing — half duration bug#2626

Open
tjiddy wants to merge 1 commit intoBorewit:masterfrom
tjiddy:fix/mdhd-v1-duration
Open

Fix mdhd/mvhd version 1 (64-bit) atom parsing — half duration bug#2626
tjiddy wants to merge 1 commit intoBorewit:masterfrom
tjiddy:fix/mdhd-v1-duration

Conversation

@tjiddy
Copy link
Copy Markdown

@tjiddy tjiddy commented Apr 8, 2026

Summary

Fixes incorrect duration parsing for MP4/M4B files that use version 1 (64-bit) mdhd and mvhd atoms. These atoms report exactly half the correct duration because the parser was hardcoded for version 0 field offsets only.

Root Cause

The ISO 14496-12 spec defines two versions of mdhd/mvhd:

  • Version 0: 4-byte creation_time, modification_time, and duration
  • Version 1: 8-byte creation_time, modification_time, and duration

Version 1 shifts the timeScale field from offset 12 to offset 20, and duration from offset 16 (4 bytes) to offset 24 (8 bytes). The parser read all fields at version 0 offsets regardless of version, causing it to read incorrect values from the middle of 64-bit fields.

Evidence

Tested with 6 M4B audiobook files. All version 1 files reported exactly half duration; all version 0 files were correct:

File mdhd version ffprobe duration music-metadata duration (before fix)
File A v1 (sz:44) 50177s (13.9h) 25089s (7.0h) ❌
File B v1 (sz:44) 100261s (27.8h) 50130s (13.9h) ❌
File C v1 (sz:44) 206811s (57.4h) 103405s (28.7h) ❌
File D v0 (sz:32) 32267s 32267s ✅
File E v0 (sz:32) 103355s 103355s ✅
File F v0 (sz:32) 36540s 36540s ✅

Changes

  • MdhdAtom.get(): Check version field; use 64-bit offsets and UINT64_BE for version 1
  • MvhdAtom.get(): Same version-aware parsing (same bug, same fix)
  • Added SecondsSinceMacEpoch64 token for 64-bit timestamp fields in version 1 atoms

Tests

All 568 existing tests pass. No regressions.

Version 1 mdhd and mvhd atoms use 64-bit fields for creation time,
modification time, and duration, shifting all subsequent field offsets
by 12 bytes compared to version 0. The parser was hardcoded for
version 0 offsets only, causing it to read the wrong bytes for
timeScale and duration on version 1 atoms.

This resulted in exactly half the correct duration being reported for
M4B audiobook files that use version 1 mdhd atoms (typically files
produced by Audible/Libation with 22050 Hz sample rate).

The fix checks the version field and uses the correct offsets for
each version. Adds a 64-bit SecondsSinceMacEpoch token for the
larger timestamp fields in version 1 atoms.
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.

1 participant