Java mp4parser 输出为空
Java mp4parser output is empty
此用例是一项服务,可将一系列未压缩的 .wav 媒体片段手动编码为 .m4s 片段,以便通过 MPEG-DASH 进行广播,使用 ffmpeg 将 .wav 压缩为 .aac,并将 sannies/mp4parser 压缩为assemble 将 aac 音频转换为 .m4s 媒体片段。
我创建了 this public GitHub project 来完整重现该问题。
例如,这里是自定义 ChunkFragmentM4sBuilder.java class.
第一个使用 MP4 盒子的例子是可行的,因为我能够生成一个初始化 MP4 + 一系列片段 M4
然后可以连接形成可播放的 MPEG4 流的文件。
注意:此用例要求每个媒体片段都从单独生成的源片段编码,而不是使用 MP4Box 等工具从连续音频源流式传输。
尝试通过 mp4parser 手动构建媒体片段总体上仍然失败,因为由
我在下面使用的 ChunkFragmentM4sBuilder.java 格式不正确。
但我很难理解 它们究竟是如何畸形的。
并排比较两个测试日志对我很有帮助
边,ChunkFragmentM4sBuilderTest.log.txt
和 MP4BoxTest.log.txt.
通过 Java mp4parser(格式错误)
前者log是
来自 ChunkFragmentM4sBuilderTest.java 这导致
连接的测试输出 test-java-mp4parser.mp4 位于
事实为空:
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();
- test5.mpd
- test5-128k-163493804.m4s
- test5-128k-163493805.m4s
- test5-128k-163493806.m4s
- test5-128k-IS.mp4
连接框:
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
通过 MP4Box(确定)
后者log是
来自 MP4BoxTest.java 的结果是串联的测试输出
test-mp4box.mp4 没关系。
但是请注意,由于这种 hack 方法输出的块中存在缺陷,因此这种方法对于最终用例是不可接受的。
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
- test5.mpd
- test5-128k-163494320.m4s
- test5-128k-163494321.m4s
- test5-128k-163494322.m4s
- test5-128k-IS.mp4
连接框:
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
test-java-mp4parser.mp4
不为空但无效,因为:
sidx
条目引用的大小错误
tfhd
正在用 0
覆盖默认样本描述索引 (1
)
trun
没有指定数据偏移量
mdat
AAC 数据以 8 个零字节开头,导致解码失败
如果这些都已修复,文件将使用 FFmpeg 播放。
列出的 m4s
段也是格式错误的,似乎与串联结果不对应。例如序号作为样本描述索引。
此用例是一项服务,可将一系列未压缩的 .wav 媒体片段手动编码为 .m4s 片段,以便通过 MPEG-DASH 进行广播,使用 ffmpeg 将 .wav 压缩为 .aac,并将 sannies/mp4parser 压缩为assemble 将 aac 音频转换为 .m4s 媒体片段。
我创建了 this public GitHub project 来完整重现该问题。
例如,这里是自定义 ChunkFragmentM4sBuilder.java class.
第一个使用 MP4 盒子的例子是可行的,因为我能够生成一个初始化 MP4 + 一系列片段 M4 然后可以连接形成可播放的 MPEG4 流的文件。
注意:此用例要求每个媒体片段都从单独生成的源片段编码,而不是使用 MP4Box 等工具从连续音频源流式传输。
尝试通过 mp4parser 手动构建媒体片段总体上仍然失败,因为由 我在下面使用的 ChunkFragmentM4sBuilder.java 格式不正确。 但我很难理解 它们究竟是如何畸形的。
并排比较两个测试日志对我很有帮助 边,ChunkFragmentM4sBuilderTest.log.txt 和 MP4BoxTest.log.txt.
通过 Java mp4parser(格式错误)
前者log是
来自 ChunkFragmentM4sBuilderTest.java 这导致
连接的测试输出 test-java-mp4parser.mp4 位于
事实为空:
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();
- test5.mpd
- test5-128k-163493804.m4s
- test5-128k-163493805.m4s
- test5-128k-163493806.m4s
- test5-128k-IS.mp4
连接框:
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
通过 MP4Box(确定)
后者log是 来自 MP4BoxTest.java 的结果是串联的测试输出 test-mp4box.mp4 没关系。
但是请注意,由于这种 hack 方法输出的块中存在缺陷,因此这种方法对于最终用例是不可接受的。
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
- test5.mpd
- test5-128k-163494320.m4s
- test5-128k-163494321.m4s
- test5-128k-163494322.m4s
- test5-128k-IS.mp4
连接框:
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
test-java-mp4parser.mp4
不为空但无效,因为:
sidx
条目引用的大小错误tfhd
正在用0
覆盖默认样本描述索引 (trun
没有指定数据偏移量mdat
AAC 数据以 8 个零字节开头,导致解码失败
1
)
如果这些都已修复,文件将使用 FFmpeg 播放。
列出的 m4s
段也是格式错误的,似乎与串联结果不对应。例如序号作为样本描述索引。