Search code examples
ffmpegmp4mpeg-dashmp4parserfmp4

Java mp4parser to create a single .m4s fragment— invalid moov box


This use case is a service that manually encodes a series of uncompressed .wav media segments into .m4s fragments for broadcast via MPEG-DASH, using ffmpeg to compress the .wav to .aac and sannies/mp4parser to assemble the aac audio into an .m4s media fragment.

I created this public GitHub project to reproduce the issue in its entirety.

For example, here's the custom CustomFragmentMp4Builder.java class.

It's critical that we be able to designate this single .m4s fragment with a sequence number (index) that we will manually increment for each media segment.

The objective is to build an .m4s fragment comprising the box types SegmentTypeBox, SegmentIndexBox, and MovieFragmentBox. As For reference, I have used mp4parser to inspect an .m4s fragment that was generated via ffmpeg -f hls. This specification is available here as a .yaml file

My implementation creates an MP4 without error. But, when the unit test attempts to read the file that the ChunkMp4Builder just wrote to a temp folder:

java.lang.RuntimeException: A cast to int has gone wrong. Please contact the mp4parser discussion group (3724673092)
    at org.mp4parser.tools.CastUtils.l2i(CastUtils.java:30)
    at org.mp4parser.support.AbstractBox.parse(AbstractBox.java:97)
    at org.mp4parser.AbstractBoxParser.parseBox(AbstractBoxParser.java:116)
    at org.mp4parser.BasicContainer.initContainer(BasicContainer.java:107)
    at org.mp4parser.IsoFile.<init>(IsoFile.java:57)
    at org.mp4parser.IsoFile.<init>(IsoFile.java:52)
    at com.charneykaye.TestBase.getMp4Boxes(TestBase.java:116)
    at com.charneykaye.CustomFragmentMp4BuilderTest.run(CustomFragmentMp4BuilderTest.java:78)

The expected box types SegmentTypeBox, SegmentIndexBox, and MovieFragmentBox do appear in the output:

The expected box types SegmentTypeBox, SegmentIndexBox, and MovieFragmentBox do appear in the output

However, at the end of the file appears a box of an unknown type:

There seems to be a box of an unknown type, appearing at the end of the file.


Solution

  • Your m4s segments are invalid due to an incorrect mdat atom size.

    For example in test5-128k-151304042.m4s the mdat is marked as having a length of 16 bytes but there is data at the end and file size is 164884.

    The parser then attempts to read an invalid offset. avc5 is not an atom but actually part of the string "Lavc58.54.100". The length read as 3724673100 is also invalid and greater than the max for a 32-bit integer, hence the invalid cast to int.

    hex dump


    In your implementation you have:

    ParsableBox moov = createMovieFragmentBox(movie);
    isoFile.addBox(moov);
    List<SampleSizeBox> stszs = Path.getPaths(moov, "trak/mdia/minf/stbl/stsz");
    // ...
    
    protected MovieFragmentBox createMovieFragmentBox(Movie movie) {
        MovieFragmentBox mfb = new MovieFragmentBox();
        // ...
    }
    

    This is not a moov atom, it's a moof. There is no stsz in there and the sum of your sample sizes is 0 so the total calculated size of the mdat is 16 + 0.

    The moov is supposed to be in the initialization segment.