mirror of
https://github.com/samsonjs/media.git
synced 2026-04-10 12:05:47 +00:00
Add E2E test for Mp4Muxer to verify overall box structure
There is no super test which covers whole MP4 structure. In all the E2E test, it verified against `ExtractorOutput` which would remain same if there are changes in the box structure. PiperOrigin-RevId: 608310006
This commit is contained in:
parent
2cd0cb30cd
commit
d097fe11d0
4 changed files with 100 additions and 20 deletions
|
|
@ -16,9 +16,12 @@
|
|||
package androidx.media3.muxer;
|
||||
|
||||
import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.XMP_SAMPLE_DATA;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.getFakeSampleAndSampleInfo;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.util.Pair;
|
||||
import androidx.media3.container.Mp4TimestampData;
|
||||
|
|
@ -43,6 +46,8 @@ import org.junit.runner.RunWith;
|
|||
public class Mp4MuxerEndToEndTest {
|
||||
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private final Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
@Test
|
||||
public void createMp4File_addTrackAndMetadataButNoSamples_createsEmptyFile() throws IOException {
|
||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||
|
|
@ -69,13 +74,13 @@ public class Mp4MuxerEndToEndTest {
|
|||
/* creationTimestampSeconds= */ 100_000_000L,
|
||||
/* modificationTimestampSeconds= */ 500_000_000L));
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 200L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 200L);
|
||||
Pair<ByteBuffer, BufferInfo> track2Sample1 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
Pair<ByteBuffer, BufferInfo> track2Sample2 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 300L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 300L);
|
||||
|
||||
try {
|
||||
TrackToken track1 = mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||
|
|
@ -98,7 +103,7 @@ public class Mp4MuxerEndToEndTest {
|
|||
FakeExtractorOutput fakeExtractorOutput =
|
||||
TestUtil.extractAllSamplesFromFilePath(new Mp4Extractor(), outputFilePath);
|
||||
DumpFileAsserts.assertOutput(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
context,
|
||||
fakeExtractorOutput,
|
||||
MuxerTestUtil.getExpectedDumpFilePath("mp4_with_same_tracks_offset.mp4"));
|
||||
}
|
||||
|
|
@ -112,13 +117,13 @@ public class Mp4MuxerEndToEndTest {
|
|||
/* creationTimestampSeconds= */ 100_000_000L,
|
||||
/* modificationTimestampSeconds= */ 500_000_000L));
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
Pair<ByteBuffer, BufferInfo> track2Sample1 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
Pair<ByteBuffer, BufferInfo> track2Sample2 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 200L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 200L);
|
||||
|
||||
try {
|
||||
TrackToken track1 = mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||
|
|
@ -137,7 +142,7 @@ public class Mp4MuxerEndToEndTest {
|
|||
FakeExtractorOutput fakeExtractorOutput =
|
||||
TestUtil.extractAllSamplesFromFilePath(new Mp4Extractor(), outputFilePath);
|
||||
DumpFileAsserts.assertOutput(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
context,
|
||||
fakeExtractorOutput,
|
||||
MuxerTestUtil.getExpectedDumpFilePath("mp4_with_different_tracks_offset.mp4"));
|
||||
}
|
||||
|
|
@ -147,11 +152,11 @@ public class Mp4MuxerEndToEndTest {
|
|||
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 2000L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 2000L);
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample3 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 1000L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 1000L);
|
||||
try {
|
||||
TrackToken track1 = mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||
mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second);
|
||||
|
|
@ -174,9 +179,9 @@ public class Mp4MuxerEndToEndTest {
|
|||
/* creationTimestampSeconds= */ 100_000_000L,
|
||||
/* modificationTimestampSeconds= */ 500_000_000L));
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample1 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
Pair<ByteBuffer, BufferInfo> track1Sample2 =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
|
||||
|
||||
try {
|
||||
TrackToken track1 = mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||
|
|
@ -194,8 +199,39 @@ public class Mp4MuxerEndToEndTest {
|
|||
new DumpableMp4Box(ByteBuffer.wrap(TestUtil.getByteArrayFromFilePath(outputFilePath)));
|
||||
// Output contains only one trak box.
|
||||
DumpFileAsserts.assertOutput(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
context, dumpableBox, MuxerTestUtil.getExpectedDumpFilePath("mp4_without_empty_track.mp4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeMp4File_withSampleAndMetadata_matchedExpectedBoxStructure() throws Exception {
|
||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||
Pair<ByteBuffer, BufferInfo> sampleAndSampleInfo =
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
byte[] xmpBytes = TestUtil.getByteArray(context, XMP_SAMPLE_DATA);
|
||||
ByteBuffer xmp = ByteBuffer.wrap(xmpBytes);
|
||||
|
||||
try {
|
||||
muxer.setOrientation(90);
|
||||
muxer.setLocation(/* latitude= */ 33.0f, /* longitude= */ -120f);
|
||||
muxer.setCaptureFps(120.0f);
|
||||
muxer.setTimestampData(
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 1_000_000L,
|
||||
/* modificationTimestampSeconds= */ 5_000_000L));
|
||||
muxer.addMetadata("StringKey1", "StringValue");
|
||||
muxer.addXmp(xmp);
|
||||
TrackToken token = muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
|
||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||
} finally {
|
||||
muxer.close();
|
||||
}
|
||||
|
||||
DumpableMp4Box dumpableBox =
|
||||
new DumpableMp4Box(ByteBuffer.wrap(TestUtil.getByteArrayFromFilePath(outputFilePath)));
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
dumpableBox,
|
||||
MuxerTestUtil.getExpectedDumpFilePath("mp4_without_empty_track.mp4"));
|
||||
MuxerTestUtil.getExpectedDumpFilePath("mp4_with_samples_and_metadata.mp4"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package androidx.media3.muxer;
|
||||
|
||||
import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.XMP_SAMPLE_DATA;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
|
|
@ -41,9 +42,6 @@ import org.junit.runner.RunWith;
|
|||
public class Mp4MuxerMetadataTest {
|
||||
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
// Input files.
|
||||
private static final String XMP_SAMPLE_DATA = "media/xmp/sample_datetime_xmp.xmp";
|
||||
|
||||
private final Context context = ApplicationProvider.getApplicationContext();
|
||||
private final Pair<ByteBuffer, BufferInfo> sampleAndSampleInfo =
|
||||
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ import java.nio.ByteBuffer;
|
|||
.setInitializationData(ImmutableList.of(FAKE_CSD_0, FAKE_CSD_1))
|
||||
.build();
|
||||
|
||||
public static final String XMP_SAMPLE_DATA = "media/xmp/sample_datetime_xmp.xmp";
|
||||
|
||||
private static final byte[] FAKE_H264_SAMPLE =
|
||||
BaseEncoding.base16()
|
||||
.decode(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
ftyp (28 bytes):
|
||||
Data = length 20, hash EF896440
|
||||
mdat (71 bytes):
|
||||
Data = length 55, hash 6B19F4A7
|
||||
moov (873 bytes):
|
||||
mvhd (108 bytes):
|
||||
Data = length 100, hash 2613A5C
|
||||
udta (38 bytes):
|
||||
Data = length 30, hash 25372BB9
|
||||
meta (177 bytes):
|
||||
hdlr (33 bytes):
|
||||
Data = length 25, hash C39D0F5B
|
||||
keys (65 bytes):
|
||||
Data = length 57, hash E97C2148
|
||||
ilst (71 bytes):
|
||||
Data = length 63, hash D81D174
|
||||
trak (542 bytes):
|
||||
tkhd (92 bytes):
|
||||
Data = length 84, hash 4ACEE52E
|
||||
mdia (442 bytes):
|
||||
mdhd (32 bytes):
|
||||
Data = length 24, hash 41542D81
|
||||
hdlr (44 bytes):
|
||||
Data = length 36, hash A0852FF2
|
||||
minf (358 bytes):
|
||||
vmhd (20 bytes):
|
||||
Data = length 12, hash EE830681
|
||||
dinf (36 bytes):
|
||||
Data = length 28, hash D535436B
|
||||
stbl (294 bytes):
|
||||
stsd (166 bytes):
|
||||
Data = length 158, hash 11532063
|
||||
stts (24 bytes):
|
||||
Data = length 16, hash E4FC6483
|
||||
stsz (24 bytes):
|
||||
Data = length 16, hash 50B7F5B9
|
||||
stsc (28 bytes):
|
||||
Data = length 20, hash 8F6E8285
|
||||
co64 (24 bytes):
|
||||
Data = length 16, hash E4EE4D2E
|
||||
stss (20 bytes):
|
||||
Data = length 12, hash EE911E03
|
||||
uuid (2853 bytes):
|
||||
Data = length 2845, hash 52AF0F9D
|
||||
Loading…
Reference in a new issue