Gapless MP4/AAC from FFmpeg: padding derived as 0 from the edit list, so the rest of the last frame plays at each join
Maintainers usually reply within 5 days
@rohitjoins is already working on this.
Since Oct 26, 2026.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Domain
- audio-video-rtc, backend
Research direction
Start by tracing how BoxParser derives encoder padding from MP4 edit lists and sample timing; the issue identifies that calculation as the source of the zero padding. Compare the reported FFmpeg edit-list values with the iTunSMPB case and check existing gapless playback tests. Done means the supplied FFmpeg AAC fixtures play for exactly N samples, including at playlist joins, without regressing the iTunSMPB case.
Written by the indexing model from the issue text.
Description
Version
Media3 pre-release (alpha, beta or RC not in this list)
More version details
Media3 1.12.0-alpha01. Also reproduced with 1.11.1.
Devices that reproduce the issue
- Android emulators, API 30, 36 and 37 (
c2.android.aac.decoder) - Samsung Galaxy S24 Ultra running Android 16 (
c2.android.aac.decoder)
Devices that do not reproduce the issue
No response
Reproducible in the demo app?
Not tested
Reproduction steps
FFmpeg's MP4 muxer (FFmpeg 9.0.2, native aac encoder, -f ipod or -f mp4) writes the gapless information of an AAC track as an edit list plus a shortened last sample:
elst: one entry,media_time= 1024 (the priming),segment_duration= the true length N;stts: every frame 1024, except the last one, which gets only the samples it really holds (N mod 1024), so that the sum ofsttsis exactly 1024 + N;- no iTunSMPB.
BoxParser derives the encoder padding from the edit list as max(0, sum of stts - end of the edit), which is 0 for these files. The decoder still outputs the whole last frame (1024 samples), so 1024 - (N mod 1024) extra samples play after the end of every track.
- Cut one continuous signal into parts whose lengths are not a multiple of 1024 and encode each with
ffmpeg -i part.wav -c:a aac -b:a 128k -f ipod part.m4a. - Play the parts as a playlist with ExoPlayer and copy the output with a
TeeAudioProcessor(it sits after the trimming). - Align the captured PCM with the source signal.
Expected result
Each track plays as exactly N samples, as FFmpeg itself decodes these files. For AAC with its fixed frame size the padding could be frames * 1024 - media_time - segment_duration, i.e. derived from what the decoder will output rather than from the stts sum.
The same encoder output remuxed without an edit list (-use_editlist 0) and with an iTunSMPB atom already plays to the sample on the same devices.
Actual result
Track 1 has N = 132357 samples (last stts delta 261), so the join after it is late by 1024 - 261 = 763 samples. Over the five tracks the joins are late by 763, 1251, 2164 and 3085 samples in total, and the album plays 532480 samples instead of 529200: up to 23 ms of padding at each join, on all the devices above.
Related: FFmpeg tickets https://trac.ffmpeg.org/ticket/8631 and https://trac.ffmpeg.org/ticket/10458 (missing end padding information in FFmpeg's MP4 output).
Media
Synthetic test files (5 tracks of one 12 s piece at 44.1 kHz), with the expected values and the generator:
- https://github.com/LordDetson/piplayer/tree/main/app/src/androidTest/assets/gapless/aac-ffmpeg (as FFmpeg writes it)
- https://github.com/LordDetson/piplayer/tree/main/app/src/androidTest/assets/gapless/aac (the same with iTunSMPB and no edit list, plays exactly)
- https://github.com/LordDetson/piplayer/blob/main/app/src/androidTest/assets/gapless/fixture.json
- https://github.com/LordDetson/piplayer/blob/main/scripts/generate_gapless_fixtures.py
Bug Report
- You will email the zip file produced by
adb bugreportto [email protected] after filing this issue.
- Dominant language
- Java
- Stars
- 3.1k
- Forks
- 998
- Avg merge
- 8d 4h
- Merged PRs (30d)
- 5
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from androidx/media
-
Cast: system output switcher on Samsung One UI 9 (Android 17) only offers Samsung Audio Mirroring, never a Cast sessionPossibly taken @tanay187 claimed this 1 day ago. Openbug cast needs triage
androidx/media#3500 · 3 comments · 2 assignees ·
Maintainers usually reply within 5 days
-
Waive ads when seek/start at the beginningPossibly taken @microkatz claimed this 3 days ago. Openenhancement
androidx/media#3496 · 3 comments · 1 assignee ·
Maintainers usually reply within 5 days
-
Since 1.9.0, skip buttons in SLOT_BACK / SLOT_FORWARD reach legacy controllers as custom actionsPossibly taken @marcbaechinger claimed this 2 days ago. Openbug
androidx/media#3495 · 1 comment · 1 assignee ·
Maintainers usually reply within 5 days
-
Allow configuring asset-list prefetch timing per HLS interstitialPossibly taken @marcbaechinger claimed this 3 days ago. Openenhancement
androidx/media#3494 · 3 comments · 1 assignee ·
Maintainers usually reply within 5 days
-
Offloaded audio left paused keeps AudioFlinger's AudioOffload wake lock forever, device never suspendsPossibly taken @microkatz claimed this 3 days ago. Openbug
androidx/media#3493 · 1 comment · 1 assignee ·
Maintainers usually reply within 5 days
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
quarkusio/quarkus-agent-mcp#302 ·
Maintainers usually reply within 2 days
-
build
Difficulty 1/5 Under an hour Newbie friendliness 85/100
MetricsHub/metricshub-community#1472 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
IdentityArrayObjectSet iterator remove may throw ArrayIndexOutOfBoundsExceptionPossibly taken @jiteshkhatri11 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
javapathfinder/jpf-core#660 · 1 comment ·