feat(mp4): convert fragmented files to progressive (defragmentation) - #557
Draft
nchitkara-xai wants to merge 1 commit into
Draft
feat(mp4): convert fragmented files to progressive (defragmentation)#557nchitkara-xai wants to merge 1 commit into
nchitkara-xai wants to merge 1 commit into
Conversation
Add mp4.Defragment and mp4.DefragmentTracks, which convert a fragmented file to a progressive one: sample tables (stts, ctts, stsc, stsz, stss, stco/co64) are synthesized from the fragment metadata while payload bytes, sample descriptions, and fragment-declared timing are preserved. Every track is rebased so that its first tfdt becomes media time zero: edit-list media times shift by the same origin, and a track starting later than the earliest one keeps its presentation alignment through an empty edit (merged into an existing leading one, prepended, or as a synthesized edit list), with at most half a movie-timescale tick of rounding. Encrypted fragments (senc or traf-level saiz/saio), backward tfdt jumps, edits that cannot be shifted exactly, truncated byte ranges, declared payloads exceeding the input file size, and kept tracks without any samples (whose empty sample tables would classify the output as fragmented again) fail closed. The new mp4ff-defragment tool exposes the conversion with optional track selection. Files with an initial progressive part before the first fragment are rejected for now; support may come as a follow-up.
This was referenced Aug 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #548, following the approach discussed there.
Problem
There is no way to convert a fragmented file to a progressive one (#162,
#311, #548): the moov of the progressive file needs the metadata of every
sample, so all moofs must be read before anything can be written.
Fix
mp4.Defragment(f *File, rs io.ReadSeeker, w io.Writer)andmp4.DefragmentTracks(f, rs, w, trackIDs...), plus a thincmd/mp4ff-defragmentCLI (cloned from the mp4ff-crop skeleton,-tfortrack selection). Two passes: sample metadata is collected from all moofs
(lazy mdat, payloads never materialized), the progressive sample tables
(stts/ctts/stsc/stsz/stss/stco/co64) are synthesized, the moov is written,
then the sample byte ranges are copied verbatim. Each traf becomes one chunk,
so the input interleaving is kept.
Timeline handling as discussed in #548: each track is rebased by its own
first tfdt, existing elst media times shift by the same amount, and differing
start offsets between tracks are absorbed with an empty edit in movie
timescale on the later track (merged into its elst or synthesized), worst
case half a movie tick of rounding. A forward tfdt gap extends the previous
sample; a backward tfdt is an error.
Fail-closed rather than silently wrong: rate != 1 and other odd edits,
encrypted tracks (senc, or saiz/saio without senc), kept tracks without
samples (init-only input), declared payload exceeding the input size, and
files that already carry progressive samples are all rejected with clear
errors — track selection doubles as the escape hatch for a single bad track.
Kept for follow-ups to stay small here: progressive-prefix (hybrid) inputs,
resolving overlapping fragments, and multi-file import (one file series per
track) as sketched in #548.
Tests
Exact elst outputs are pinned for differing origins with no/existing/leading
empty edits and for equal origins; conversion round-trips are verified
sample-by-sample against re-decoded output; all fragmented testdata files
(AAC, Opus, VVC, multi-segment, decrypted cbcs) convert and re-decode as
progressive; error paths cover encryption, backward tfdt, truncation,
amplification, hybrid input, and sample-less tracks.
go test ./...,go vet,gofmt,golangci-lintpass.