javamp4mpegmp4parserfmp4

Java mp4parser output is empty


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 a .m4s media fragment.

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

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


The first example using MP4 box works, insofar as I am able to generate an initializing MP4 + series of fragment M4s files which can then be concatenated to form a playable MPEG4 stream.

Note: it's a requirement for this use case that each media segment is encoded from an individually generated source segment, versus using a tool such as MP4Box to stream from a continuous audio source.

Attempts to manually build media segments via mp4parser are still failing overall, because the fragments written by my ChunkFragmentM4sBuilder.java used below are malformed. But I'm having a difficult time understanding how exactly they are malformed.

It's been helpful for me to compare the two test logs side by side, ChunkFragmentM4sBuilderTest.log.txt and MP4BoxTest.log.txt.

via Java mp4parser (malformed)

The former log is from ChunkFragmentM4sBuilderTest.java which results in the concatenated test output test-java-mp4parser.mp4 which is in fact empty: Concatenated output from Java mp4parser method is empty

Files.deleteIfExists(Path.of(m4sFilePath));
AACTrackImpl aacTrack=new AACTrackImpl(new FileDataSourceImpl(aacFilePath));
Movie movie=new Movie();
movie.addTrack(aacTrack);
Container mp4file=new ChunkFragmentM4sBuilder(hz,seconds,seqNum,bufferSize).build(movie);
FileChannel fc=new FileOutputStream(m4sFilePath).getChannel();
mp4file.writeContainer(fc);
fc.close();

Concatenated boxes:

FileTypeBox[majorBrand=iso5;minorVersion=512;compatibleBrand=iso6;compatibleBrand=mp41]
MovieBox[MovieHeaderBox[creationTime=Thu Dec 31 16:00:00 PST 1903;modificationTime=Thu Dec 31 16:00:00 PST 1903;timescale=1000;duration=0;rate=1.0;volume=1.0;matrix=Rotate 0°;nextTrackId=2];TrackBox[TrackHeaderBox[creationTime=Thu Dec 31 16:00:00 PST 1903;modificationTime=Thu Dec 31 16:00:00 PST 1903;trackId=1;duration=0;layer=0;alternateGroup=1;volume=1.0;matrix=Rotate 0°;width=0.0;height=0.0];EditBox[EditListBox{entries=[Entry{segmentDuration=0, mediaTime=1024, mediaRate=1.0}]}];MediaBox[MediaHeaderBox[creationTime=Thu Dec 31 16:00:00 PST 1903;modificationTime=Thu Dec 31 16:00:00 PST 1903;timescale=48000;duration=0;language=und];HandlerBox[handlerType=soun;name=SoundHandler];MediaInformationBox[SoundMediaHeaderBox[balance=0.0];DataInformationBox[DataReferenceBox[DataEntryUrlBox[]]];SampleTableBox[SampleDescriptionBox[AudioSampleEntry{bytesPerSample=0, bytesPerFrame=0, bytesPerPacket=0, samplesPerPacket=0, packetSize=0, compressionId=0, soundVersion=0, sampleRate=48000, sampleSize=16, channelCount=2, boxes=[org.mp4parser.boxes.iso14496.part14.ESDescriptorBox@bed094d2]}];TimeToSampleBox[entryCount=0];SampleToChunkBox[entryCount=0];SampleSizeBox[sampleSize=0;sampleCount=0];StaticChunkOffsetBox[entryCount=0]]]]];MovieExtendsBox[org.mp4parser.boxes.iso14496.part12.TrackExtendsBox@11e7301d];UserDataBox[MetaBox[HandlerBox[handlerType=mdir;name=];AppleItemListBox[org.mp4parser.boxes.apple.AppleEncoderBox@691fba4]]]]
SegmentTypeBox[majorBrand=msdh;minorVersion=0;compatibleBrand=msdh;compatibleBrand=msix]
SegmentIndexBox{entries=[Entry{referenceType=0, referencedSize=160944, subsegmentDuration=480000, startsWithSap=1, sapType=0, sapDeltaTime=0}], referenceId=1, timeScale=48000, earliestPresentationTime=0, firstOffset=0, reserved=0}
MovieFragmentBox[MovieFragmentHeaderBox{sequenceNumber=151304042};TrackFragmentBox[TrackFragmentHeaderBox{trackId=1, baseDataOffset=-1, sampleDescriptionIndex=0, defaultSampleDuration=-1, defaultSampleSize=-1, defaultSampleFlags=null, durationIsEmpty=true, defaultBaseIsMoof=true};TrackFragmentBaseMediaDecodeTimeBox{baseMediaDecodeTime=0};TrackRunBox{sampleCount=470, dataOffset=-1, dataOffsetPresent=false, sampleSizePresent=true, sampleDurationPresent=true, sampleFlagsPresentPresent=false, sampleCompositionTimeOffsetPresent=false, firstSampleFlags=null}]]
org.mp4parser.boxes.iso14496.part12.MediaDataBox@3969adb0

via MP4Box (ok)

The latter log is from MP4BoxTest.java which results in the concatenated test output test-mp4box.mp4 which is OK.

Note however, this method is not acceptable for the final use case, because of the imperfections in the blocks that are output by this hack method.

Concatenated output from MP4Box method is ok

MP4Box \
  -profile live \
  -add aacFilePath \
  -dash 10000 \
  -frag 10000 \
  -idx ${NUM} \
  -moof-sn ${NUM} \
  -out test5.mpd \
  -segment-name test5-128k- \
  -segment-ext m4s \
  -single-traf \
  -subsegs-per-sidx 0 \
  -daisy-chain \
  -single-segment \
  /tmp

Concatenated boxes:

FileTypeBox[majorBrand=iso5;minorVersion=512;compatibleBrand=iso6;compatibleBrand=mp41]
MovieBox[MovieHeaderBox[creationTime=Thu Dec 31 16:00:00 PST 1903;modificationTime=Thu Dec 31 16:00:00 PST 1903;timescale=1000;duration=0;rate=1.0;volume=1.0;matrix=Rotate 0°;nextTrackId=2];TrackBox[TrackHeaderBox[creationTime=Thu Dec 31 16:00:00 PST 1903;modificationTime=Thu Dec 31 16:00:00 PST 1903;trackId=1;duration=0;layer=0;alternateGroup=1;volume=1.0;matrix=Rotate 0°;width=0.0;height=0.0];EditBox[EditListBox{entries=[Entry{segmentDuration=0, mediaTime=1024, mediaRate=1.0}]}];MediaBox[MediaHeaderBox[creationTime=Thu Dec 31 16:00:00 PST 1903;modificationTime=Thu Dec 31 16:00:00 PST 1903;timescale=48000;duration=0;language=und];HandlerBox[handlerType=soun;name=SoundHandler];MediaInformationBox[SoundMediaHeaderBox[balance=0.0];DataInformationBox[DataReferenceBox[DataEntryUrlBox[]]];SampleTableBox[SampleDescriptionBox[AudioSampleEntry{bytesPerSample=0, bytesPerFrame=0, bytesPerPacket=0, samplesPerPacket=0, packetSize=0, compressionId=0, soundVersion=0, sampleRate=48000, sampleSize=16, channelCount=2, boxes=[org.mp4parser.boxes.iso14496.part14.ESDescriptorBox@bed094d2]}];TimeToSampleBox[entryCount=0];SampleToChunkBox[entryCount=0];SampleSizeBox[sampleSize=0;sampleCount=0];StaticChunkOffsetBox[entryCount=0]]]]];MovieExtendsBox[org.mp4parser.boxes.iso14496.part12.TrackExtendsBox@7ce1e496];UserDataBox[MetaBox[HandlerBox[handlerType=mdir;name=];AppleItemListBox[org.mp4parser.boxes.apple.AppleEncoderBox@51da5351]]]]
SegmentTypeBox[majorBrand=msdh;minorVersion=0;compatibleBrand=msdh;compatibleBrand=msix]
SegmentIndexBox{entries=[Entry{referenceType=0, referencedSize=162267, subsegmentDuration=479232, startsWithSap=1, sapType=1, sapDeltaTime=0}], referenceId=1, timeScale=48000, earliestPresentationTime=0, firstOffset=0, reserved=0}
MovieFragmentBox[MovieFragmentHeaderBox{sequenceNumber=151304042};TrackFragmentBox[TrackFragmentHeaderBox{trackId=1, baseDataOffset=-1, sampleDescriptionIndex=0, defaultSampleDuration=-1, defaultSampleSize=-1, defaultSampleFlags=null, durationIsEmpty=false, defaultBaseIsMoof=true};TrackFragmentBaseMediaDecodeTimeBox{baseMediaDecodeTime=0};TrackRunBox{sampleCount=468, dataOffset=1964, dataOffsetPresent=true, sampleSizePresent=true, sampleDurationPresent=false, sampleFlagsPresentPresent=false, sampleCompositionTimeOffsetPresent=false, firstSampleFlags=null}]]
org.mp4parser.boxes.iso14496.part12.MediaDataBox@640d3ba5

Solution

  • test-java-mp4parser.mp4 is not empty but is invalid because:

    The file plays with FFmpeg if these are fixed.

    The m4s segments listed are also malformed and don't seem to correspond to the concatenation result. For example the sequence number is used as the sample description index.