Skip to content

Ignore parse errors on trailing data after the mdat atom of MP4 streams - #147

Open
chrizzchrizz wants to merge 1 commit into
dimitris-c:mainfrom
chrizzchrizz:fix/mp4-trailing-padding
Open

chrizzchrizz wants to merge 1 commit into
dimitris-c:mainfrom
chrizzchrizz:fix/mp4-trailing-padding

Conversation

@chrizzchrizz

Copy link
Copy Markdown

Problem

Some M4A files carry trailing data after the mdat atom, for example zero bytes left as padding by tag editors. Once the stream reaches it, AudioFileStreamParseBytes fails with kAudioFileStreamError_InvalidFile ('dta?'), although every audio packet has been parsed already. The player then raises streamParseBytesFailure while the entry is still playing, about one buffer length before the audible end of the track.

Seen with a real file: ftyp, moov, free, mdat (ends at byte 4885649), then 32648 zero bytes up to the end of the file. The same happens with a plain AudioFileStream outside the library, and all 7756 audio packets are delivered before the error.

Change

  • AudioFileStreamProcessor tracks the stream byte offset of the data passed to the parser (reset on open, set to the seek offset in processSeek).
  • If parsing fails for an M4A/MPEG4 stream once that offset is past dataOffset + audioDataByteCount, the error is ignored and the rest of the stream is dropped. The final flush is skipped in that case.
  • All bytes are still passed to the parser as before. Nothing is truncated ahead of time, so no audio can be lost even if audioDataByteCount is smaller than the mdat atom (e.g. chapter tracks inside mdat). Errors inside the audio data are reported as before.
  • Other formats are unchanged.

Tests

Mp4TrailingDataTests:

  • A small AAC m4a fixture with 4096 zero bytes after mdat, fed in 1 KB chunks through AudioFileStreamProcessor: all chunks and the final flush return noErr and no error is raised. Without the change this test fails with 1685348671 ('dta?') at the chunk that crosses the end of mdat.
  • Unit tests for the boundary check (inside, at the end, after the end, unknown byte count).

The full test suite passes on macOS.

Some M4A files carry trailing padding after mdat (e.g. zero bytes left by
tag editors). AudioFileStreamParseBytes rejects it with
kAudioFileStreamError_InvalidFile once the stream reaches it, although all
audio packets have been parsed already, which raised
streamParseBytesFailure shortly before the end of the song.

Track the stream byte offset passed to the parser. When parsing fails after
dataOffset + audioDataByteCount of an MP4 stream, ignore the error and the
rest of the stream. All bytes are still parsed as before, so no audio can be
dropped, and errors inside the audio data are reported as before.
@chrizzchrizz

chrizzchrizz commented Oct 19, 2026 •

Copy link
Copy Markdown
Author

Audio streaming isn't my area of expertise. So I had to rely on Claude Code to fix the issue. In my opinion, it worked well and the bug is gone, but I need your expertise for the final assessment.

Thx
Chrizz

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