diff --git a/library/extractor/build.gradle b/library/extractor/build.gradle index 839d13c38a..0d4ef9abfd 100644 --- a/library/extractor/build.gradle +++ b/library/extractor/build.gradle @@ -19,7 +19,11 @@ android { testCoverageEnabled = true } } - + testOptions{ + unitTests.all { + jvmArgs '-noverify' + } + } sourceSets.test.assets.srcDir '../../testdata/src/test/assets/' } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vAviTrack.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vAviTrack.java index ff0962ece0..d5a02962c8 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vAviTrack.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/avi/Mp4vAviTrack.java @@ -1,6 +1,8 @@ package com.google.android.exoplayer2.extractor.avi; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.TrackOutput; @@ -13,7 +15,7 @@ public class Mp4vAviTrack extends AviTrack { private static final float[] ASPECT_RATIO = {0f, 1f, 12f/11f, 10f/11f, 16f/11f, 40f/33f}; private static final int Extended_PAR = 0xf; private final Format.Builder formatBuilder; - private float pixelWidthHeightRatio = 1f; + float pixelWidthHeightRatio = 1f; Mp4vAviTrack(int id, @NonNull StreamHeaderBox streamHeaderBox, @NonNull TrackOutput trackOutput, @NonNull Format.Builder formatBuilder) { @@ -21,8 +23,8 @@ public class Mp4vAviTrack extends AviTrack { this.formatBuilder = formatBuilder; } - private void processLayerStart(byte[] peek, int offset) { - final ParsableNalUnitBitArray in = new ParsableNalUnitBitArray(peek, offset, peek.length); + @VisibleForTesting + void processLayerStart(@NonNull final ParsableNalUnitBitArray in) { in.skipBit(); // random_accessible_vol in.skipBits(8); // video_object_type_indication boolean is_object_layer_identifier = in.readBit(); @@ -44,23 +46,35 @@ public class Mp4vAviTrack extends AviTrack { } } - private void seekLayerStart(ExtractorInput input) throws IOException { - byte[] peek = new byte[128]; - input.peekFully(peek, 0, peek.length); + @VisibleForTesting + @Nullable + static ParsableNalUnitBitArray findLayerStart(ExtractorInput input, final int peekSize) + throws IOException { + byte[] peek = new byte[peekSize]; + input.peekFully(peek, 0, peekSize); for (int i = 4;i STREAM_MAP = new SparseArray<>(); @@ -30,7 +32,7 @@ public class StreamHeaderBox extends ResidentBox { STREAM_MAP.put('A' | ('V' << 8) | ('C' << 16) | ('1' << 24), MimeTypes.VIDEO_H264); STREAM_MAP.put('3' | ('V' << 8) | ('I' << 16) | ('D' << 24), mimeType); STREAM_MAP.put('x' | ('v' << 8) | ('i' << 16) | ('d' << 24), mimeType); - STREAM_MAP.put('X' | ('V' << 8) | ('I' << 16) | ('D' << 24), mimeType); + STREAM_MAP.put(XVID, mimeType); STREAM_MAP.put('D' | ('X' << 8) | ('5' << 16) | ('0' << 24), mimeType); STREAM_MAP.put('m' | ('j' << 8) | ('p' << 16) | ('g' << 24), MimeTypes.VIDEO_JPEG); @@ -86,15 +88,17 @@ public class StreamHeaderBox extends ResidentBox { public int getRate() { return byteBuffer.getInt(24); } - public int getStart() { - return byteBuffer.getInt(28); - } + // 28 - dwStart +// public int getStart() { +// return byteBuffer.getInt(28); +// } public long getLength() { return byteBuffer.getInt(32) & AviExtractor.UINT_MASK; } //36 - dwSuggestedBufferSize //40 - dwQuality - public int getSampleSize() { - return byteBuffer.getInt(44); - } + //44 - dwSampleSize +// public int getSampleSize() { +// return byteBuffer.getInt(44); +// } } diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/DataHelper.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/DataHelper.java new file mode 100644 index 0000000000..b60472bcb6 --- /dev/null +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/DataHelper.java @@ -0,0 +1,32 @@ +package com.google.android.exoplayer2.extractor.avi; + +import com.google.android.exoplayer2.testutil.FakeExtractorInput; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class DataHelper { + //Base path "\ExoPlayer\library\extractor\." + private static final File RELATIVE_PATH = new File("../../testdata/src/test/assets/extractordumps/avi/"); + public static FakeExtractorInput getInput(final String fileName) throws IOException { + return new FakeExtractorInput.Builder().setData(getBytes(fileName)).build(); + } + + public static byte[] getBytes(final String fileName) throws IOException { + final File file = new File(RELATIVE_PATH, fileName); + try (FileInputStream in = new FileInputStream(file)) { + final byte[] buffer = new byte[in.available()]; + in.read(buffer); + return buffer; + } + } + + public static StreamHeaderBox getVidsStreamHeader() throws IOException { + final byte[] buffer = getBytes("vids_stream_header.dump"); + final ByteBuffer byteBuffer = ByteBuffer.wrap(buffer); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + return new StreamHeaderBox(StreamHeaderBox.STRH, buffer.length, byteBuffer); + } +} diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/Mp4vAviTrackTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/Mp4vAviTrackTest.java new file mode 100644 index 0000000000..c14352f4aa --- /dev/null +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/Mp4vAviTrackTest.java @@ -0,0 +1,51 @@ +package com.google.android.exoplayer2.extractor.avi; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.testutil.FakeExtractorInput; +import com.google.android.exoplayer2.testutil.FakeTrackOutput; +import com.google.android.exoplayer2.util.ParsableNalUnitBitArray; +import java.io.IOException; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class Mp4vAviTrackTest { + + @Test + public void isSequenceStart_givenSequence() throws IOException { + final FakeExtractorInput input = DataHelper.getInput("mp4v_sequence.dump"); + Assert.assertTrue(Mp4vAviTrack.isSequenceStart(input)); + } + + @Test + public void findLayerStart_givenSequence() throws IOException { + final FakeExtractorInput input = DataHelper.getInput("mp4v_sequence.dump"); + final ParsableNalUnitBitArray bitArray = Mp4vAviTrack.findLayerStart(input, + (int)input.getLength()); + //Offset 0x12 + Assert.assertEquals(8, bitArray.readBits(8)); + } + + @Test + public void findLayerStart_givenAllZeros() throws IOException { + final FakeExtractorInput fakeExtractorInput = new FakeExtractorInput.Builder(). + setData(new byte[128]).build(); + Assert.assertNull(Mp4vAviTrack.findLayerStart(fakeExtractorInput, 128)); + } + + @Test + public void pixelWidthHeightRatio_givenSequence() throws IOException { + final FakeTrackOutput fakeTrackOutput = new FakeTrackOutput(false); + final Format.Builder formatBuilder = new Format.Builder(); + final Mp4vAviTrack mp4vAviTrack = new Mp4vAviTrack(0, DataHelper.getVidsStreamHeader(), + fakeTrackOutput, formatBuilder); + final FakeExtractorInput input = DataHelper.getInput("mp4v_sequence.dump"); + mp4vAviTrack.newChunk(0, (int)input.getLength(), input); +// final ParsableNalUnitBitArray bitArray = Mp4vAviTrack.findLayerStart(input, +// (int)input.getLength()); +// mp4vAviTrack.processLayerStart(bitArray); + Assert.assertEquals(mp4vAviTrack.pixelWidthHeightRatio, 1.2121212, 0.01); + } +} diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/StreamHeaderBoxTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/StreamHeaderBoxTest.java new file mode 100644 index 0000000000..e56ce01dfc --- /dev/null +++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/avi/StreamHeaderBoxTest.java @@ -0,0 +1,29 @@ +package com.google.android.exoplayer2.extractor.avi; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.android.exoplayer2.util.MimeTypes; +import java.io.IOException; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class StreamHeaderBoxTest { + private static float FPS24 = 24000f/1001f; + private static final long US_SAMPLE24FPS = (long)(1_000_000L / FPS24); + + @Test + public void getters_givenXvidStreamHeader() throws IOException { + final StreamHeaderBox streamHeaderBox = DataHelper.getVidsStreamHeader(); + + Assert.assertTrue(streamHeaderBox.isVideo()); + Assert.assertFalse(streamHeaderBox.isAudio()); + Assert.assertEquals(StreamHeaderBox.VIDS, streamHeaderBox.getSteamType()); + Assert.assertEquals(StreamHeaderBox.XVID, streamHeaderBox.getFourCC()); + Assert.assertEquals(0, streamHeaderBox.getInitialFrames()); + Assert.assertEquals(FPS24, streamHeaderBox.getFrameRate(), 0.1); + Assert.assertEquals(US_SAMPLE24FPS, streamHeaderBox.getUsPerSample()); + Assert.assertEquals(MimeTypes.VIDEO_MP4V, streamHeaderBox.getMimeType()); + Assert.assertEquals(11805L, streamHeaderBox.getLength()); + } +} diff --git a/testdata/src/test/assets/extractordumps/avi/mp4v_sequence.dump b/testdata/src/test/assets/extractordumps/avi/mp4v_sequence.dump new file mode 100644 index 0000000000..6859c2b7dd Binary files /dev/null and b/testdata/src/test/assets/extractordumps/avi/mp4v_sequence.dump differ diff --git a/testdata/src/test/assets/extractordumps/avi/vids_stream_header.dump b/testdata/src/test/assets/extractordumps/avi/vids_stream_header.dump new file mode 100644 index 0000000000..d7e95e2df3 Binary files /dev/null and b/testdata/src/test/assets/extractordumps/avi/vids_stream_header.dump differ