GStreamer can output a single-file fragmented MP4, using a pipeline like this:
❯ gst-launch-1.0 filesrc location=../test.ts ! decodebin ! x264enc ! ismlmux fragment-duration=6000 faststart=1 ! filesink location=fragmented.mp4
Using Bento4, we can confirm that the file contains interleaved moof
and mdat
atoms (I'm filtering for top-level atoms only since the full output is very long):
❯ mp4dump fragmented.mp4 | egrep '^[^ ]'
[ftyp] size=8+16
[moov] size=8+833
[moof] size=8+5112
[mdat] size=8+538271
[moof] size=8+2964
[mdat] size=8+296190
[moof] size=8+5112
[mdat] size=8+484946
[moof] size=8+2964
[mdat] size=8+305615
[moof] size=8+5112
[mdat] size=8+482052
[moof] size=8+2964
[mdat] size=8+298039
[moof] size=8+5112
[mdat] size=8+478313
[moof] size=8+2964
[mdat] size=8+294548
[moof] size=8+5112
[mdat] size=8+483575
[moof] size=8+2964
[mdat] size=8+303894
[moof] size=8+5112
[mdat] size=8+483527
[moof] size=8+2964
[mdat] size=8+316919
Using Bento4, we can also split the file into separate files -- init.mp4
containing the initial metadata, and a file for each moof
+mdat
pair.
❯ mp4split fragmented.mp4
❯ ls
fragmented.mp4 segment-1.0001.m4s segment-1.0003.m4s segment-1.0005.m4s segment-1.0007.m4s segment-1.0009.m4s segment-1.0011.m4s
init.mp4 segment-1.0002.m4s segment-1.0004.m4s segment-1.0006.m4s segment-1.0008.m4s segment-1.0010.m4s segment-1.0012.m4s
❯ mp4dump init.mp4 | egrep '^[^ ]'
[ftyp] size=8+16
[moov] size=8+833
[udta] size=8+53
[mvex] size=8+52
❯ mp4dump segment-1.0001.m4s | egrep '^[^ ]'
[moof] size=8+5112
[mdat] size=8+538271
However, mp4split
needs the full file first in order to split it, and I need to support live streaming, meaning that this approach is infeasible. Is there a way to output the fMP4 split into multiple files directly from GStreamer?
I tried splitmuxsink, but it seems to produce individually playable independent MP4 files, not fragments. I also tried using multifilesink to save the fragmented MP4, but there doesn't seem to be a way to tell it to split the file at specific atoms.