From cb7ea09af1af54ec220f6dedb64cb6eaa1be62be Mon Sep 17 00:00:00 2001 From: sheenachhabra Date: Wed, 31 Jan 2024 10:28:57 -0800 Subject: [PATCH] Add regression test of skipping empty track when writing MP4 The implementation of fragmented MP4 caused a regression where muxer started writing empty tracks even for non fragmented MP4. PiperOrigin-RevId: 603091348 --- .../media3/muxer/Mp4MuxerEndToEndTest.java | 32 ++++++++++++++++++ .../mp4_without_empty_track.mp4.dump | 33 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump diff --git a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java index 99a6f65c56..430993e75e 100644 --- a/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java +++ b/libraries/muxer/src/test/java/androidx/media3/muxer/Mp4MuxerEndToEndTest.java @@ -24,6 +24,7 @@ import android.util.Pair; import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.muxer.Mp4Muxer.TrackToken; import androidx.media3.test.utils.DumpFileAsserts; +import androidx.media3.test.utils.DumpableMp4Box; import androidx.media3.test.utils.FakeExtractorOutput; import androidx.media3.test.utils.TestUtil; import androidx.test.core.app.ApplicationProvider; @@ -156,4 +157,35 @@ public class Mp4MuxerEndToEndTest { mp4Muxer.close(); } } + + @Test + public void createMp4File_withOneTrackEmpty_doesNotWriteEmptyTrack() throws Exception { + String outputFilePath = temporaryFolder.newFile().getPath(); + Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build(); + mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L); + Pair track1Sample1 = + MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L); + Pair track1Sample2 = + MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L); + + try { + TrackToken track1 = mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT); + mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second); + mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second); + // Add same track again but without any samples. + mp4Muxer.addTrack(/* sortKey= */ 1, FAKE_VIDEO_FORMAT); + } finally { + mp4Muxer.close(); + } + + // The FakeExtractorOutput omits tracks with no samples so the dump file will be the same + // with/without the empty track. Hence used DumpableMp4Box instead. + DumpableMp4Box dumpableBox = + new DumpableMp4Box(ByteBuffer.wrap(TestUtil.getByteArrayFromFilePath(outputFilePath))); + // Output contains only one trak box. + DumpFileAsserts.assertOutput( + ApplicationProvider.getApplicationContext(), + dumpableBox, + MuxerTestUtil.getExpectedDumpFilePath("mp4_without_empty_track.mp4")); + } } diff --git a/libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump b/libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump new file mode 100644 index 0000000000..40d8ae50c6 --- /dev/null +++ b/libraries/test_data/src/test/assets/muxerdumps/mp4_without_empty_track.mp4.dump @@ -0,0 +1,33 @@ +ftyp (28 bytes): + Data = length 20, hash EF896440 +mdat (126 bytes): + Data = length 110, hash 48173D41 +moov (674 bytes): + mvhd (108 bytes): + Data = length 100, hash 3D6D026F + trak (558 bytes): + tkhd (92 bytes): + Data = length 84, hash 3EFBEC22 + mdia (458 bytes): + mdhd (32 bytes): + Data = length 24, hash 42F40E1C + hdlr (44 bytes): + Data = length 36, hash A0852FF2 + minf (374 bytes): + vmhd (20 bytes): + Data = length 12, hash EE830681 + dinf (36 bytes): + Data = length 28, hash D535436B + stbl (310 bytes): + stsd (166 bytes): + Data = length 158, hash 11532063 + stts (32 bytes): + Data = length 24, hash 4A7D0E0E + stsz (28 bytes): + Data = length 20, hash 3828E071 + stsc (28 bytes): + Data = length 20, hash 8F7C9A06 + co64 (24 bytes): + Data = length 16, hash E4EE4D2E + stss (24 bytes): + Data = length 16, hash 7940D386