You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
FragmentedMp4Muxer: missing mehd and zero moov durations cause duration=0 (and playback failure) in platform extractors #3430
Open the Gallery app (system app from Samsung device), observe the duration and try to play it.
Expected result
The duration of the video should display correctly (10s)
[The video should be playable on Gallery app (system app from Samsung device)]
Screen_Recording_20260925_002217_Gallery.mp4
Actual result
The duration is displayed as 00:00/00:00
[And the video is not playable]
Screen_Recording_20260925_002131_Gallery.mp4
Media
This is the fmp4 file produced by Demo Transfomer
transformer-output-47579613.mp4
This is the same fmp4 as above, except one thing: I just override the mvhd and mdhd with correct duration (2s). Using this video, the gallery app can display duration correctly and played normally.
transformer-output-47579613_patched.mp4
I believe that this issue mostly relies on specific device. Since using the same output, copy it to difference device (like the S21 FE), the duration is displayed correctly and it is also playable from the Gallery app.
Thanks for raising this and sharing the detailed analysis!
Generally speaking with regards to how the FragmentedMp4Muxer (used by InAppFragmentedMp4Muxer.Factory) works:
Per ISO/IEC 14496-12, the mvhd, tkhd, and mdhd durations in moov only describe samples present in the initial movie's sample table (stbl). In a fully fragmented MP4 where all samples live inside moof fragments, those durations are required to be 0 (setting non-zero tkhd/mdhd durations when stbl is empty breaks spec-compliant MSE/DASH players).
Total duration for a fragmented MP4 is instead signaled using the mehd (Movie Extends Header) box inside moov.mvex or derived from the fragments/mfra box (which is why Android 15 and 16 display the duration and play the file normally). FragmentedMp4Muxer currently omits mehd because it operates on an append-only WritableByteChannel and writes moov at the start before the total duration is known.
To help us understand your use case:
Do you specifically need fragmented MP4 ("Produce Fragmented Mp4" / InAppFragmentedMp4Muxer) for your workflow (e.g., for streaming or progressive output), or does standard MP4 (leaving "Produce Fragmented Mp4" unchecked / using InAppMp4Muxer, which writes moov at the start with populated mvhd/tkhd/mdhd durations) work for you?
If you do require fragmented MP4 on Android 12, are you able to check whether adding a mehd box inside moov.mvex (while keeping mvhd/tkhd/mdhd at 0) is sufficient for the Android 12 Samsung Gallery app to play the file?
Hi @snow2405 , thanks for the detailed explanation!
1. Do we need fragmented MP4?
Yes. Our use case runs transcoding and uploading at the same time: fragments are uploaded as soon as they are written. A standard MP4 doesn't work for this, because InAppMp4Muxer has to seek back to the start of the file at the end to finalize moov. By then, the beginning of the file has already been uploaded.
I understand that, per the spec, the mvhd/tkhd/mdhd durations must stay 0 in a fully fragmented file. On the mehd side, the muxer is append-only, but in transcoding scenarios the caller usually knows the expected output duration before muxing starts. Would it be possible to add an option to FragmentedMp4Muxer.Builder, such as setDurationHintUs(long), so that the muxer can write mehd into moov.mvex immediately? The muxer could keep omitting mehd when no hint is provided.
2. Is mehd sufficient for the Samsung Gallery app?
Unfortunately, no. I patched the output to add a correct mehd box inside moov.mvex, keeping mvhd/tkhd/mdhd at 0. The issue still reproduces on some Samsung devices (tested via Samsung Remote Test Lab). ExoPlayer reads the duration correctly from mehd, so I think the option would still help other players that support it.
The results seem to depend on the Gallery app version rather than the Android version. On Android 13, Gallery 14.0.x fails while Gallery 14.5.x works:
Device
Android
Gallery
Result
Galaxy M53 (SM-M536B)
12
13.1.04.3
❌
Galaxy M12 (SM-M127G)
12
13.1.04.04
❌
Galaxy A32 (SM-A325F)
12
13.1.04.3
❌
Galaxy A53 5G (SM-A536E)
12
13.1.05.16
❌
Galaxy S20+ (SM-G985F)
13
14.0.00.37
❌
Galaxy Note20 5G (SM-N981U)
13
14.5.00.33
✅
Galaxy A32 5G (SM-A326B)
13
14.5.00.36
✅
Galaxy A13 5G (SM-A136B)
14
15.1.03.12
✅
Galaxy S21 FE 5G (SM-G990B)
14
15.1.03.12
✅
So this looks like a limitation of older Samsung Gallery versions (below roughly 14.5), which seem to rely only on mvhd/mdhd. This matches my original test, where setting non-zero mvhd/mdhd durations made the file play.
Activity
snow2405 commentedon Oct 19, 2026
Hi @ninh-huynh
Thanks for raising this and sharing the detailed analysis!
Generally speaking with regards to how the
FragmentedMp4Muxer(used byInAppFragmentedMp4Muxer.Factory) works:mvhd,tkhd, andmdhddurations inmoovonly describe samples present in the initial movie's sample table (stbl). In a fully fragmented MP4 where all samples live insidemooffragments, those durations are required to be0(setting non-zerotkhd/mdhddurations whenstblis empty breaks spec-compliant MSE/DASH players).mehd(Movie Extends Header) box insidemoov.mvexor derived from the fragments/mfrabox (which is why Android 15 and 16 display the duration and play the file normally).FragmentedMp4Muxercurrently omitsmehdbecause it operates on an append-onlyWritableByteChanneland writesmoovat the start before the total duration is known.To help us understand your use case:
InAppFragmentedMp4Muxer) for your workflow (e.g., for streaming or progressive output), or does standard MP4 (leaving "Produce Fragmented Mp4" unchecked / usingInAppMp4Muxer, which writesmoovat the start with populatedmvhd/tkhd/mdhddurations) work for you?mehdbox insidemoov.mvex(while keepingmvhd/tkhd/mdhdat0) is sufficient for the Android 12 Samsung Gallery app to play the file?ninh-huynh commentedon Oct 21, 2026
Hi @snow2405 , thanks for the detailed explanation!
1. Do we need fragmented MP4?
Yes. Our use case runs transcoding and uploading at the same time: fragments are uploaded as soon as they are written. A standard MP4 doesn't work for this, because
InAppMp4Muxerhas to seek back to the start of the file at the end to finalizemoov. By then, the beginning of the file has already been uploaded.I understand that, per the spec, the
mvhd/tkhd/mdhddurations must stay0in a fully fragmented file. On themehdside, the muxer is append-only, but in transcoding scenarios the caller usually knows the expected output duration before muxing starts. Would it be possible to add an option toFragmentedMp4Muxer.Builder, such assetDurationHintUs(long), so that the muxer can writemehdintomoov.mveximmediately? The muxer could keep omittingmehdwhen no hint is provided.2. Is
mehdsufficient for the Samsung Gallery app?Unfortunately, no. I patched the output to add a correct
mehdbox insidemoov.mvex, keepingmvhd/tkhd/mdhdat0. The issue still reproduces on some Samsung devices (tested via Samsung Remote Test Lab). ExoPlayer reads the duration correctly frommehd, so I think the option would still help other players that support it.The results seem to depend on the Gallery app version rather than the Android version. On Android 13, Gallery 14.0.x fails while Gallery 14.5.x works:
So this looks like a limitation of older Samsung Gallery versions (below roughly 14.5), which seem to rely only on
mvhd/mdhd. This matches my original test, where setting non-zeromvhd/mdhddurations made the file play.