diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ExtractorTest.java index d4bbbee9b4..0c3062f4ba 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ExtractorTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ExtractorTest.java @@ -24,7 +24,7 @@ import junit.framework.TestCase; */ public class ExtractorTest extends TestCase { - public static void testContants() { + public static void testConstants() { // Sanity check that constant values match those defined by {@link C}. assertEquals(C.RESULT_END_OF_INPUT, Extractor.RESULT_END_OF_INPUT); // Sanity check that the other constant values don't overlap. diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractorTest.java index c96f5dc03b..0dc3083174 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractorTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/mkv/MatroskaExtractorTest.java @@ -15,788 +15,16 @@ */ package com.google.android.exoplayer.extractor.mkv; -import static com.google.android.exoplayer.extractor.mkv.StreamBuilder.TEST_ENCRYPTION_KEY_ID; - -import com.google.android.exoplayer.C; -import com.google.android.exoplayer.Format; -import com.google.android.exoplayer.ParserException; -import com.google.android.exoplayer.drm.DrmInitData; -import com.google.android.exoplayer.drm.DrmInitData.SchemeData; -import com.google.android.exoplayer.extractor.ChunkIndex; import com.google.android.exoplayer.extractor.Extractor; -import com.google.android.exoplayer.extractor.mkv.StreamBuilder.ContentEncodingSettings; -import com.google.android.exoplayer.testutil.FakeExtractorOutput; -import com.google.android.exoplayer.testutil.FakeTrackOutput; import com.google.android.exoplayer.testutil.TestUtil; -import com.google.android.exoplayer.util.MimeTypes; -import com.google.android.exoplayer.util.Util; import android.test.InstrumentationTestCase; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.UUID; - /** * Tests for {@link MatroskaExtractor}. */ public final class MatroskaExtractorTest extends InstrumentationTestCase { - private static final int DEFAULT_TIMECODE_SCALE = 1000000; - private static final long TEST_DURATION_TIMECODE = 9920L; - private static final int TEST_WIDTH = 1280; - private static final int TEST_HEIGHT = 720; - private static final int TEST_CHANNEL_COUNT = 1; - private static final int TEST_SAMPLE_RATE = 48000; - private static final int TEST_CODEC_DELAY = 6500000; - private static final int TEST_SEEK_PRE_ROLL = 80000000; - private static final String TEST_VORBIS_CODEC_PRIVATE = "webm/vorbis_codec_private"; - private static final int TEST_VORBIS_INFO_SIZE = 30; - private static final int TEST_VORBIS_BOOKS_SIZE = 4140; - private static final byte[] TEST_OPUS_CODEC_PRIVATE = new byte[] {0, 0}; - private static final int TEST_DEFAULT_DURATION_NS = 33 * 1000 * 1000; - private static final byte[] TEST_H264_CODEC_PRIVATE = TestUtil.createByteArray(0x01, 0x4D, - 0x40, 0x1E, 0xFF, 0xE1, 0x00, 0x17, 0x67, 0x4D, 0x40, 0x1E, 0xE8, 0x80, 0x50, 0x17, 0xFC, - 0xB8, 0x08, 0x80, 0x00, 0x01, 0xF4, 0x80, 0x00, 0x75, 0x30, 0x07, 0x8B, 0x16, 0x89, 0x01, - 0x00, 0x04, 0x68, 0xEB, 0xEF, 0x20); - private static final byte VIDEO_TRACK_NUMBER = 0x01; - private static final byte AUDIO_TRACK_NUMBER = 0x02; - private static final byte UNSUPPORTED_TRACK_NUMBER = 0x03; - private static final byte SECOND_VIDEO_TRACK_NUMBER = 0x04; - private static final byte SECOND_AUDIO_TRACK_NUMBER = 0x05; - - private static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL); - private static final String MATROSKA_DOC_TYPE = "matroska"; - private static final String WEBM_DOC_TYPE = "webm"; - - private FakeExtractorOutput consumeTestData(byte[] data) - throws IOException, InterruptedException { - return TestUtil.consumeTestData(new MatroskaExtractor(), data); - } - - public void testReadInitializationSegment() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareOpus() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareVorbis() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVorbisTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, - getVorbisCodecPrivate()) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_VORBIS); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareH264() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(MATROSKA_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addH264Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, TEST_H264_CODEC_PRIVATE) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertH264VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareTwoTracks() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareThreeTracks() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addUnsupportedTrack(UNSUPPORTED_TRACK_NUMBER) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - // Even though the input stream has 3 tracks, only 2 of them are supported and will be reported. - assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareFourTracks() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addVorbisTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, - getVorbisCodecPrivate()) - .addVp9Track(SECOND_VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(SECOND_AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, - TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertEquals(4, extractorOutput.numberOfTracks); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_VORBIS); - assertVp9VideoFormat(extractorOutput, SECOND_VIDEO_TRACK_NUMBER); - assertAudioFormat(extractorOutput, SECOND_AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareContentEncodingEncryption() throws IOException, InterruptedException { - ContentEncodingSettings settings = new StreamBuilder.ContentEncodingSettings(0, 1, 5, 1); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertDrmInitData(extractorOutput, VIDEO_TRACK_NUMBER); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 1); - } - - public void testPrepareThreeCuePoints() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .build(3); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSeekMap(extractorOutput, DEFAULT_TIMECODE_SCALE, 3); - } - - public void testPrepareCustomTimecodeScaleBeforeDuration() - throws IOException, InterruptedException { - testPrepareTimecodeScale(1000, false, false); - } - - public void testPrepareCustomTimecodeScaleAfterDuration() - throws IOException, InterruptedException { - testPrepareTimecodeScale(1000, false, true); - } - - public void testPrepareImplicitDefaultTimecode() - throws IOException, InterruptedException { - testPrepareTimecodeScale(1000, false, true); - } - - private void testPrepareTimecodeScale(int timecodeScale, boolean omitTimecodeScaleIfDefault, - boolean afterDuration) throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(timecodeScale, TEST_DURATION_TIMECODE, omitTimecodeScaleIfDefault, afterDuration) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .build(3); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSeekMap(extractorOutput, timecodeScale, 3); - } - - public void testPrepareNoCuesElement() throws IOException, InterruptedException { - testPrepareNoCuesElement(DEFAULT_TIMECODE_SCALE); - } - - public void testPrepareNoCuesElementCustomTimecodeScale() - throws IOException, InterruptedException { - testPrepareNoCuesElement(1000); - } - - private void testPrepareNoCuesElement(int timecodeScale) throws IOException, - InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(timecodeScale, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .build(0); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertSeekMapUnseekable(extractorOutput, timecodeScale); - } - - public void testAcceptsWebmDocType() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - } - - public void testAcceptsMatroskaDocType() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader(MATROSKA_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - } - - public void testPrepareInvalidDocType() throws IOException, InterruptedException { - byte[] data = new StreamBuilder() - .setHeader("webB") - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .build(1); - try { - consumeTestData(data); - fail(); - } catch (ParserException exception) { - assertEquals("DocType webB not supported", exception.getMessage()); - } - } - - public void testPrepareInvalidContentEncodingOrder() throws IOException, InterruptedException { - ContentEncodingSettings settings = new ContentEncodingSettings(1, 1, 5, 1); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .build(1); - try { - consumeTestData(data); - fail(); - } catch (ParserException exception) { - assertEquals("ContentEncodingOrder 1 not supported", exception.getMessage()); - } - } - - public void testPrepareInvalidContentEncodingScope() throws IOException, InterruptedException { - ContentEncodingSettings settings = new ContentEncodingSettings(0, 0, 5, 1); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .build(1); - try { - consumeTestData(data); - fail(); - } catch (ParserException exception) { - assertEquals("ContentEncodingScope 0 not supported", exception.getMessage()); - } - } - - public void testPrepareInvalidContentCompAlgo() - throws IOException, InterruptedException { - ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 0, new byte[0]); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .build(1); - try { - consumeTestData(data); - fail(); - } catch (ParserException exception) { - assertEquals("ContentCompAlgo 0 not supported", exception.getMessage()); - } - } - - public void testPrepareInvalidContentEncAlgo() throws IOException, InterruptedException { - ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 4, 1); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .build(1); - try { - consumeTestData(data); - fail(); - } catch (ParserException exception) { - assertEquals("ContentEncAlgo 4 not supported", exception.getMessage()); - } - } - - public void testPrepareInvalidAESSettingsCipherMode() throws IOException, InterruptedException { - ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 0); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .build(1); - try { - consumeTestData(data); - fail(); - } catch (ParserException exception) { - assertEquals("AESSettingsCipherMode 0 not supported", exception.getMessage()); - } - } - - public void testReadSampleKeyframe() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, media, 0, true, false, null, - getTrackOutput(extractorOutput, VIDEO_TRACK_NUMBER)); - } - - public void testReadSampleKeyframeStripped() throws IOException, InterruptedException { - byte[] strippedBytes = new byte[] {-1, -1}; - ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 3, strippedBytes); - byte[] sampleBytes = createFrameData(100); - byte[] unstrippedSampleBytes = TestUtil.joinByteArrays(strippedBytes, sampleBytes); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, sampleBytes) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, unstrippedSampleBytes, 0, true, false, null, - getTrackOutput(extractorOutput, VIDEO_TRACK_NUMBER)); - } - - public void testReadSampleKeyframeManyBytesStripped() throws IOException, InterruptedException { - byte[] strippedBytes = createFrameData(100); - ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 3, strippedBytes); - byte[] sampleBytes = createFrameData(5); - byte[] unstrippedSampleBytes = TestUtil.joinByteArrays(strippedBytes, sampleBytes); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, sampleBytes) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, unstrippedSampleBytes, 0, true, false, null, - getTrackOutput(extractorOutput, VIDEO_TRACK_NUMBER)); - } - - public void testReadTwoTrackSamples() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) - .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .addSimpleBlockMedia(2 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSample(0, media, 0, true, false, null, - getTrackOutput(extractorOutput, VIDEO_TRACK_NUMBER)); - assertSample(0, media, 0, true, false, null, - getTrackOutput(extractorOutput, AUDIO_TRACK_NUMBER)); - } - - public void testReadTwoTrackSamplesWithSkippedTrack() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addUnsupportedTrack(UNSUPPORTED_TRACK_NUMBER) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) - .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .addSimpleBlockMedia(2 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .addSimpleBlockMedia(17 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSample(0, media, 0, true, false, null, - getTrackOutput(extractorOutput, VIDEO_TRACK_NUMBER)); - assertSample(0, media, 0, true, false, null, - getTrackOutput(extractorOutput, AUDIO_TRACK_NUMBER)); - } - - public void testReadBlock() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) - .addBlockMedia(2 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - true /* keyframe */, false /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSample(0, media, 0, true, false, null, - getTrackOutput(extractorOutput, AUDIO_TRACK_NUMBER)); - } - - public void testReadBlockNonKeyframe() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, - false /* keyframe */, false /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, media, 0, false, false, null, getTrackOutput(extractorOutput, VIDEO_TRACK_NUMBER - )); - } - - public void testReadEncryptedFrame() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 1); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */, - 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, - true /* validSignalByte */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, media, 0, true, false, TEST_ENCRYPTION_KEY_ID, - getTrackOutput(extractorOutput, VIDEO_TRACK_NUMBER)); - } - - public void testReadEncryptedFrameWithInvalidSignalByte() - throws IOException, InterruptedException { - byte[] media = createFrameData(100); - ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 5, 1); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) - .addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */, - 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, - false /* validSignalByte */, media) - .build(1); - - try { - consumeTestData(data); - fail(); - } catch (ParserException exception) { - assertEquals("Extension bit is set in signal byte", exception.getMessage()); - } - } - - public void testReadSampleInvisible() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */, - false /* keyframe */, true /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, media, 25000, false, true, null, getTrackOutput(extractorOutput, - VIDEO_TRACK_NUMBER - )); - } - - public void testReadSampleCustomTimecodeScale() throws IOException, InterruptedException { - int timecodeScale = 1000; - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(timecodeScale, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */, - false /* keyframe */, false /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, media, 25, false, false, null, getTrackOutput(extractorOutput, - VIDEO_TRACK_NUMBER - )); - } - - public void testReadSampleNegativeSimpleBlockTimecode() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) - .addSimpleBlockMedia(1 /* trackNumber */, 13 /* clusterTimecode */, -12 /* blockTimecode */, - true /* keyframe */, true /* invisible */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertVp9VideoFormat(extractorOutput, VIDEO_TRACK_NUMBER); - assertSample(0, media, 1000, true, true, null, getTrackOutput(extractorOutput, - VIDEO_TRACK_NUMBER - )); - } - - public void testReadSampleWithFixedSizeLacing() throws IOException, InterruptedException { - byte[] media = createFrameData(100); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS) - .addSimpleBlockMediaWithFixedSizeLacing(2 /* trackNumber */, 0 /* clusterTimecode */, - 0 /* blockTimecode */, 20 /* lacingFrameCount */, media) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - for (int i = 0; i < 20; i++) { - long expectedTimeUs = i * TEST_DEFAULT_DURATION_NS / 1000; - assertSample(i, Arrays.copyOfRange(media, i * 5, i * 5 + 5), expectedTimeUs, true, false, - null, getTrackOutput(extractorOutput, AUDIO_TRACK_NUMBER)); - } - } - - public void testReadSampleWithXiphLacing() throws IOException, InterruptedException { - byte[] media = createFrameData(300); - byte[] data = new StreamBuilder() - .setHeader(WEBM_DOC_TYPE) - .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS) - .addSimpleBlockMediaWithXiphLacing(2 /* trackNumber */, 0 /* clusterTimecode */, - 0 /* blockTimecode */, media, 256, 1, 243) - .build(1); - - FakeExtractorOutput extractorOutput = consumeTestData(data); - - assertTracksEnded(extractorOutput); - assertAudioFormat(extractorOutput, AUDIO_TRACK_NUMBER, MimeTypes.AUDIO_OPUS); - assertSample(0, Arrays.copyOfRange(media, 0, 256), 0 * TEST_DEFAULT_DURATION_NS / 1000, true, - false, null, getTrackOutput(extractorOutput, AUDIO_TRACK_NUMBER)); - assertSample(1, Arrays.copyOfRange(media, 256, 257), 1 * TEST_DEFAULT_DURATION_NS / 1000, true, - false, null, getTrackOutput(extractorOutput, AUDIO_TRACK_NUMBER)); - assertSample(2, Arrays.copyOfRange(media, 257, 300), 2 * TEST_DEFAULT_DURATION_NS / 1000, true, - false, null, getTrackOutput(extractorOutput, AUDIO_TRACK_NUMBER)); - } - - private FakeTrackOutput getTrackOutput(FakeExtractorOutput extractorOutput, int trackNumber) { - return extractorOutput.trackOutputs.get(trackNumber); - } - - private void assertTracksEnded(FakeExtractorOutput extractorOutput) { - assertTrue(extractorOutput.tracksEnded); - } - - private void assertVp9VideoFormat(FakeExtractorOutput extractorOutput, int trackNumber) { - Format format = getTrackOutput(extractorOutput, trackNumber).format; - assertEquals(TEST_WIDTH, format.width); - assertEquals(TEST_HEIGHT, format.height); - assertEquals(MimeTypes.VIDEO_VP9, format.sampleMimeType); - } - - private void assertH264VideoFormat(FakeExtractorOutput extractorOutput, int trackNumber) { - Format format = getTrackOutput(extractorOutput, trackNumber).format; - assertEquals(TEST_WIDTH, format.width); - assertEquals(TEST_HEIGHT, format.height); - assertEquals(MimeTypes.VIDEO_H264, format.sampleMimeType); - } - - private void assertAudioFormat(FakeExtractorOutput extractorOutput, int trackNumber, - String expectedMimeType) { - Format format = getTrackOutput(extractorOutput, trackNumber).format; - assertEquals(TEST_CHANNEL_COUNT, format.channelCount); - assertEquals(TEST_SAMPLE_RATE, format.sampleRate); - assertEquals(expectedMimeType, format.sampleMimeType); - if (MimeTypes.AUDIO_OPUS.equals(expectedMimeType)) { - assertEquals(3, format.initializationData.size()); - android.test.MoreAsserts.assertEquals(TEST_OPUS_CODEC_PRIVATE, - format.initializationData.get(0)); - assertEquals(TEST_CODEC_DELAY, ByteBuffer.wrap(format.initializationData.get(1)) - .order(ByteOrder.nativeOrder()).getLong()); - assertEquals(TEST_SEEK_PRE_ROLL, ByteBuffer.wrap(format.initializationData.get(2)) - .order(ByteOrder.nativeOrder()).getLong()); - } else if (MimeTypes.AUDIO_VORBIS.equals(expectedMimeType)) { - assertEquals(2, format.initializationData.size()); - assertEquals(TEST_VORBIS_INFO_SIZE, format.initializationData.get(0).length); - assertEquals(TEST_VORBIS_BOOKS_SIZE, format.initializationData.get(1).length); - } - } - - private void assertDrmInitData(FakeExtractorOutput extractorOutput, int trackNumber) { - DrmInitData drmInitData = getTrackOutput(extractorOutput, trackNumber).format.drmInitData; - assertNotNull(drmInitData); - SchemeData widevineInitData = drmInitData.get(WIDEVINE_UUID); - assertEquals(MimeTypes.VIDEO_WEBM, widevineInitData.mimeType); - android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, widevineInitData.data); - SchemeData zeroInitData = drmInitData.get(C.UUID_NIL); - assertEquals(MimeTypes.VIDEO_WEBM, zeroInitData.mimeType); - android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, zeroInitData.data); - } - - private void assertSeekMap(FakeExtractorOutput extractorOutput, int timecodeScale, - int cuePointCount) { - ChunkIndex index = (ChunkIndex) extractorOutput.seekMap; - assertEquals(cuePointCount, index.length); - for (int i = 0; i < cuePointCount - 1; i++) { - assertEquals(Util.scaleLargeTimestamp(10 * i, timecodeScale, 1000), index.timesUs[i]); - assertEquals(Util.scaleLargeTimestamp(10, timecodeScale, 1000), index.durationsUs[i]); - assertEquals(0, index.sizes[i]); - } - int lastIndex = cuePointCount - 1; - long lastTimecode = 10 * lastIndex; - long lastDurationTimecode = TEST_DURATION_TIMECODE - lastTimecode; - assertEquals(Util.scaleLargeTimestamp(lastTimecode, timecodeScale, 1000), - index.timesUs[lastIndex]); - assertEquals(Util.scaleLargeTimestamp(lastDurationTimecode, timecodeScale, 1000), - index.durationsUs[lastIndex]); - assertEquals(Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000), - extractorOutput.seekMap.getDurationUs()); - } - - private void assertSeekMapUnseekable(FakeExtractorOutput extractorOutput, long timecodeScale) { - assertFalse(extractorOutput.seekMap.isSeekable()); - long expectedDurationUs = Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000); - assertEquals(expectedDurationUs, extractorOutput.seekMap.getDurationUs()); - } - - private void assertSample(int index, byte[] expectedMedia, long timeUs, boolean keyframe, - boolean invisible, byte[] encryptionKey, FakeTrackOutput output) { - if (encryptionKey != null) { - expectedMedia = TestUtil.joinByteArrays( - new byte[] {(byte) StreamBuilder.TEST_INITIALIZATION_VECTOR.length}, - StreamBuilder.TEST_INITIALIZATION_VECTOR, expectedMedia); - } - int flags = 0; - flags |= keyframe ? C.BUFFER_FLAG_KEY_FRAME : 0; - flags |= invisible ? C.BUFFER_FLAG_DECODE_ONLY : 0; - flags |= encryptionKey != null ? C.BUFFER_FLAG_ENCRYPTED : 0; - output.assertSample(index, expectedMedia, timeUs, flags, encryptionKey); - } - - private byte[] getVorbisCodecPrivate() throws IOException { - return TestUtil.getByteArray(getInstrumentation(), TEST_VORBIS_CODEC_PRIVATE); - } - - private static byte[] createFrameData(int size) { - byte[] data = new byte[size]; - for (int i = 0; i < size; i++) { - data[i] = (byte) i; - } - return data; - } - public void testMkvSample() throws Exception { TestUtil.assertOutput(new TestUtil.ExtractorFactory() { @Override @@ -805,4 +33,5 @@ public final class MatroskaExtractorTest extends InstrumentationTestCase { } }, "mkv/sample.mkv", getInstrumentation()); } + } diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/mkv/StreamBuilder.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/mkv/StreamBuilder.java deleted file mode 100644 index 1e8126ce53..0000000000 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/mkv/StreamBuilder.java +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer.extractor.mkv; - -import com.google.android.exoplayer.testutil.TestUtil; -import com.google.android.exoplayer.util.Assertions; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * Provides byte arrays containing Matroska data for {@link MatroskaExtractorTest}. - */ -/* package */ final class StreamBuilder { - - /** Used by {@link #addVp9Track} to create a track header with encryption/compression. */ - public static final class ContentEncodingSettings { - - private final int order; - private final int scope; - private final int type; - private final int algorithm; - private final int aesCipherMode; - private final byte[] strippedBytes; - - public ContentEncodingSettings(int order, int scope, int algorithm, int aesCipherMode) { - this.order = order; - this.scope = scope; - this.type = 1; // Encryption - this.algorithm = algorithm; - this.aesCipherMode = aesCipherMode; - this.strippedBytes = null; - } - - public ContentEncodingSettings(int order, int scope, int algorithm, byte[] strippedBytes) { - this.order = order; - this.scope = scope; - this.type = 0; // Compression - this.algorithm = algorithm; - this.aesCipherMode = 0; - this.strippedBytes = strippedBytes; - } - - } - - public static final byte[] TEST_ENCRYPTION_KEY_ID = { 0x00, 0x01, 0x02, 0x03 }; - public static final byte[] TEST_INITIALIZATION_VECTOR = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - }; - - private static final int NO_VALUE = -1; - - private final List trackEntries; - private final List mediaSegments; - - private EbmlElement header; - private EbmlElement info; - - public StreamBuilder() { - trackEntries = new LinkedList<>(); - mediaSegments = new LinkedList<>(); - } - - public StreamBuilder setHeader(String docType) { - header = createEbmlElement(1, docType, 2); - return this; - } - - public StreamBuilder setInfo(int timecodeScale, long durationTimecode) { - return setInfo(timecodeScale, durationTimecode, false, false); - } - - public StreamBuilder setInfo(int timecodeScale, long durationTimecode, - boolean omitTimecodeScaleIfDefault, boolean durationFirst) { - info = createInfoElement(timecodeScale, durationTimecode, omitTimecodeScaleIfDefault, - durationFirst); - return this; - } - - public StreamBuilder addVp9Track(byte trackNumber, int width, int height, - ContentEncodingSettings contentEncodingSettings) { - trackEntries.add(createVideoTrackEntry(trackNumber, "V_VP9", width, height, - contentEncodingSettings, null)); - return this; - } - - public StreamBuilder addH264Track(byte trackNumber, int width, int height, byte[] codecPrivate) { - trackEntries.add(createVideoTrackEntry(trackNumber, "V_MPEG4/ISO/AVC", width, height, null, - codecPrivate)); - return this; - } - - public StreamBuilder addOpusTrack(byte trackNumber, int channelCount, int sampleRate, - int codecDelay, int seekPreRoll, byte[] codecPrivate) { - trackEntries.add(createAudioTrackEntry(trackNumber, "A_OPUS", channelCount, sampleRate, - codecPrivate, codecDelay, seekPreRoll, NO_VALUE)); - return this; - } - - public StreamBuilder addOpusTrack(byte trackNumber, int channelCount, int sampleRate, - int codecDelay, int seekPreRoll, byte[] codecPrivate, int defaultDurationNs) { - trackEntries.add(createAudioTrackEntry(trackNumber, "A_OPUS", channelCount, sampleRate, - codecPrivate, codecDelay, seekPreRoll, defaultDurationNs)); - return this; - } - - public StreamBuilder addVorbisTrack(byte trackNumber, int channelCount, int sampleRate, - byte[] codecPrivate) { - trackEntries.add(createAudioTrackEntry(trackNumber, "A_VORBIS", channelCount, sampleRate, - codecPrivate, NO_VALUE, NO_VALUE, NO_VALUE)); - return this; - } - - public StreamBuilder addUnsupportedTrack(byte trackNumber) { - trackEntries.add(element(0xAE, // TrackEntry - element(0x86, "D_WEBVTT/metadata".getBytes()), // CodecID - element(0xD7, trackNumber), // TrackNumber - element(0x83, (byte) 0x11))); // TrackType - return this; - } - - public StreamBuilder addSimpleBlockEncryptedMedia(int trackNumber, int clusterTimecode, - int blockTimecode, boolean keyframe, boolean invisible, boolean validSignalByte, - byte[] data) { - int flags = (keyframe ? 0x80 : 0x00) | (invisible ? 0x08 : 0x00); - EbmlElement simpleBlockElement = createSimpleBlock(trackNumber, blockTimecode, flags, true, - validSignalByte, 1, data); - mediaSegments.add(createCluster(clusterTimecode, simpleBlockElement)); - return this; - } - - - public StreamBuilder addSimpleBlockMedia(int trackNumber, int clusterTimecode, - int blockTimecode, boolean keyframe, boolean invisible, byte[] data) { - int flags = (keyframe ? 0x80 : 0x00) | (invisible ? 0x08 : 0x00); - EbmlElement simpleBlockElement = createSimpleBlock(trackNumber, blockTimecode, flags, false, - true, 1, data); - mediaSegments.add(createCluster(clusterTimecode, simpleBlockElement)); - return this; - } - - public StreamBuilder addSimpleBlockMediaWithFixedSizeLacing(int trackNumber, int clusterTimecode, - int blockTimecode, int lacingFrameCount, byte[] data) { - EbmlElement simpleBlockElement = createSimpleBlock(trackNumber, blockTimecode, - 0x80 /* flags = keyframe */, false, true, lacingFrameCount, data); - mediaSegments.add(createCluster(clusterTimecode, simpleBlockElement)); - return this; - } - - public StreamBuilder addSimpleBlockMediaWithXiphLacing(int trackNumber, int clusterTimecode, - int blockTimecode, byte[] data, int... lacingFrameSizes) { - EbmlElement simpleBlockElement = createSimpleBlock(trackNumber, blockTimecode, - 0x80 /* flags = keyframe */, false, true, data, lacingFrameSizes); - mediaSegments.add(createCluster(clusterTimecode, simpleBlockElement)); - return this; - } - - public StreamBuilder addBlockMedia(int trackNumber, int clusterTimecode, int blockTimecode, - boolean keyframe, boolean invisible, byte[] data) { - byte flags = (byte) (invisible ? 0x08 : 0x00); - EbmlElement blockElement = - createBlock(trackNumber, blockTimecode, keyframe, flags, data); - mediaSegments.add(createCluster(clusterTimecode, blockElement)); - return this; - } - - /** - * Serializes the constructed stream to a {@code byte[]} using the specified number of cue points. - */ - public byte[] build(int cuePointCount) { - Assertions.checkNotNull(header); - Assertions.checkNotNull(info); - - EbmlElement tracks = element(0x1654AE6B, - trackEntries.toArray(new EbmlElement[trackEntries.size()])); - EbmlElement[] children; - - if (cuePointCount == 0) { - children = new EbmlElement[2 + mediaSegments.size()]; - System.arraycopy(mediaSegments.toArray(), 0, children, 2, mediaSegments.size()); - children[0] = info; - children[1] = tracks; - } else { - // Get the size of the initialization segment. - EbmlElement[] cuePointElements = new EbmlElement[cuePointCount]; - for (int i = 0; i < cuePointCount; i++) { - cuePointElements[i] = createCuePointElement(10 * i, 0); - } - EbmlElement cues = element(0x1C53BB6B, cuePointElements); // Cues - long initializationSegmentSize = info.getSize() + tracks.getSize() + cues.getSize(); - - // Recreate the initialization segment using its size as an offset. - for (int i = 0; i < cuePointCount; i++) { - cuePointElements[i] = createCuePointElement(10 * i, (int) initializationSegmentSize); - } - cues = element(0x1C53BB6B, cuePointElements); // Cues - - // Build the top-level segment element. - children = new EbmlElement[3 + mediaSegments.size()]; - System.arraycopy(mediaSegments.toArray(), 0, children, 3, mediaSegments.size()); - children[0] = info; - children[1] = tracks; - children[2] = cues; - } - - EbmlElement segmentElement = element(0x18538067, children); // Segment - - // Serialize the EBML header and the top-level segment element. - return EbmlElement.serialize(header, segmentElement); - } - - private static EbmlElement createCuePointElement(int cueTime, int cueClusterPosition) { - byte[] positionBytes = getLongBytes(cueClusterPosition); - return element(0xBB, // CuePoint - element(0xB3, (byte) (cueTime & 0xFF)), // CueTime - element(0xB7, // CueTrackPositions - element(0xF1, positionBytes))); // CueClusterPosition - } - - private static EbmlElement createEbmlElement(int ebmlReadVersion, String docType, - int docTypeReadVersion) { - return element(0x1A45DFA3, // EBML - element(0x42F7, (byte) (ebmlReadVersion & 0xFF)), // EBMLReadVersion - element(0x4282, docType.getBytes()), // DocType - element(0x4285, (byte) (docTypeReadVersion & 0xFF))); // DocTypeReadVersion - } - - private EbmlElement createInfoElement(int timecodeScale, long durationTimecode, - boolean durationFirst, boolean omitDefaultTimecodeScale) { - byte[] timecodeScaleBytes = getIntegerBytes(timecodeScale); - byte[] durationBytes = getLongBytes(Double.doubleToLongBits(durationTimecode)); - EbmlElement durationElement = element(0x4489, durationBytes); - EbmlElement timescaleElement = element(0x2AD7B1, timecodeScaleBytes); - if (omitDefaultTimecodeScale && timecodeScale == 1000000) { - return element(0x1549A966, // Info - durationElement); - } - return element(0x1549A966, // Info - durationFirst ? durationElement : timescaleElement, - durationFirst ? timescaleElement : durationElement); - } - - private static EbmlElement createVideoTrackEntry(byte trackNumber, String codecId, int pixelWidth, - int pixelHeight, ContentEncodingSettings contentEncodingSettings, byte[] codecPrivate) { - byte[] widthBytes = getIntegerBytes(pixelWidth); - byte[] heightBytes = getIntegerBytes(pixelHeight); - EbmlElement contentEncodingSettingsElement; - if (contentEncodingSettings != null) { - EbmlElement encryptionOrCompressionElement; - if (contentEncodingSettings.type == 0) { - encryptionOrCompressionElement = element(0x5034, // ContentCompression - element(0x4254, (byte) (contentEncodingSettings.algorithm & 0xFF)), // ContentCompAlgo - element(0x4255, contentEncodingSettings.strippedBytes)); // ContentCompSettings - } else if (contentEncodingSettings.type == 1) { - encryptionOrCompressionElement = element(0x5035, // ContentEncryption - // ContentEncAlgo - element(0x47E1, (byte) (contentEncodingSettings.algorithm & 0xFF)), - element(0x47E2, TEST_ENCRYPTION_KEY_ID), // ContentEncKeyID - element(0x47E7, // ContentEncAESSettings - // AESSettingsCipherMode - element(0x47E8, (byte) (contentEncodingSettings.aesCipherMode & 0xFF)))); - } else { - throw new IllegalArgumentException("Unexpected encoding type."); - } - - contentEncodingSettingsElement = - element(0x6D80, // ContentEncodings - element(0x6240, // ContentEncoding - // ContentEncodingOrder - element(0x5031, (byte) (contentEncodingSettings.order & 0xFF)), - // ContentEncodingScope - element(0x5032, (byte) (contentEncodingSettings.scope & 0xFF)), - // ContentEncodingType - element(0x5033, (byte) (contentEncodingSettings.type & 0xFF)), - encryptionOrCompressionElement)); - } else { - contentEncodingSettingsElement = empty(); - } - EbmlElement codecPrivateElement; - if (codecPrivate != null) { - codecPrivateElement = element(0x63A2, codecPrivate); // CodecPrivate - } else { - codecPrivateElement = empty(); - } - - return element(0xAE, // TrackEntry - element(0x86, codecId.getBytes()), // CodecID - element(0xD7, trackNumber), // TrackNumber - element(0x83, (byte) 0x01), // TrackType - contentEncodingSettingsElement, - element(0xE0, // Video - element(0xB0, widthBytes[2], widthBytes[3]), - element(0xBA, heightBytes[2], heightBytes[3])), - codecPrivateElement); - } - - private static EbmlElement createAudioTrackEntry(byte trackNumber, String codecId, - int channelCount, int sampleRate, byte[] codecPrivate, int codecDelay, int seekPreRoll, - int defaultDurationNs) { - byte channelCountByte = (byte) (channelCount & 0xFF); - byte[] sampleRateDoubleBytes = getLongBytes(Double.doubleToLongBits(sampleRate)); - return element(0xAE, // TrackEntry - element(0x86, codecId.getBytes()), // CodecID - element(0xD7, trackNumber), // TrackNumber - element(0x83, (byte) 0x02), // TrackType - // CodecDelay - codecDelay != NO_VALUE ? element(0x56AA, getIntegerBytes(codecDelay)) : empty(), - // SeekPreRoll - seekPreRoll != NO_VALUE ? element(0x56BB, getIntegerBytes(seekPreRoll)) : empty(), - element(0xE1, // Audio - element(0x9F, channelCountByte), // Channels - element(0xB5, sampleRateDoubleBytes)), // SamplingFrequency - // DefaultDuration - defaultDurationNs != NO_VALUE ? element(0x23E383, getIntegerBytes(defaultDurationNs)) - : empty(), - element(0x63A2, codecPrivate)); // CodecPrivate - } - - private static EbmlElement createCluster(int timecode, EbmlElement blockGroupOrSimpleBlock) { - return element(0x1F43B675, // Cluster - element(0xE7, getIntegerBytes(timecode)), // Timecode - blockGroupOrSimpleBlock); - } - - private static EbmlElement createSimpleBlock(int trackNumber, int timecode, int flags, - boolean encrypted, boolean validSignalByte, int lacingFrameCount, byte[] data) { - byte[] trackNumberBytes = getIntegerBytes(trackNumber); - byte[] timeBytes = getIntegerBytes(timecode); - byte[] simpleBlockBytes; - if (lacingFrameCount > 1) { - flags |= 0x04; // Fixed-size lacing - simpleBlockBytes = TestUtil.joinByteArrays( - new byte[] {0x40, trackNumberBytes[3], timeBytes[2], timeBytes[3]}, - TestUtil.createByteArray(flags, lacingFrameCount - 1)); - } else { - simpleBlockBytes = TestUtil.joinByteArrays( - new byte[] {0x40, trackNumberBytes[3], timeBytes[2], timeBytes[3]}, - TestUtil.createByteArray(flags)); - } - if (encrypted) { - simpleBlockBytes = TestUtil.joinByteArrays( - simpleBlockBytes, TestUtil.createByteArray(validSignalByte ? 0x01 : 0x80), - Arrays.copyOfRange(TEST_INITIALIZATION_VECTOR, 0, 8)); - } - return element(0xA3, // SimpleBlock - TestUtil.joinByteArrays(simpleBlockBytes, data)); - } - - private static EbmlElement createSimpleBlock(int trackNumber, int timecode, int flags, - boolean encrypted, boolean validSignalByte, byte[] data, int... xiphLacingSampleSizes) { - byte[] trackNumberBytes = getIntegerBytes(trackNumber); - byte[] timeBytes = getIntegerBytes(timecode); - byte[] simpleBlockBytes; - flags |= 0x02; // Xiph lacing - simpleBlockBytes = TestUtil.createByteArray( - 0x40, trackNumberBytes[3], // Track number size=2 - timeBytes[2], timeBytes[3], // Timecode - flags, xiphLacingSampleSizes.length - 1); // Flags and lacing. - int lacingBufferSize = 0; - for (int sampleIndex = 0; sampleIndex < xiphLacingSampleSizes.length - 1; sampleIndex++) { - lacingBufferSize += (xiphLacingSampleSizes[sampleIndex] + 254) / 255; - } - ByteBuffer lacingBytes = ByteBuffer.allocate(lacingBufferSize); - for (int sampleIndex = 0; sampleIndex < xiphLacingSampleSizes.length - 1; sampleIndex++) { - int sampleSize = xiphLacingSampleSizes[sampleIndex]; - while (sampleSize > 255) { - sampleSize -= 255; - lacingBytes.put((byte) 0xFF); - } - lacingBytes.put((byte) sampleSize); - } - simpleBlockBytes = TestUtil.joinByteArrays(simpleBlockBytes, lacingBytes.array()); - - if (encrypted) { - simpleBlockBytes = TestUtil.joinByteArrays( - simpleBlockBytes, TestUtil.createByteArray(validSignalByte ? 0x01 : 0x80), - Arrays.copyOfRange(TEST_INITIALIZATION_VECTOR, 0, 8)); - } - return element(0xA3, // SimpleBlock - TestUtil.joinByteArrays(simpleBlockBytes, data)); - } - - private static EbmlElement createBlock(int trackNumber, int timecode, boolean keyframe, int flags, - byte[] data) { - byte[] trackNumberBytes = getIntegerBytes(trackNumber); - byte[] timeBytes = getIntegerBytes(timecode); - byte[] blockBytes = TestUtil.createByteArray( - 0x40, trackNumberBytes[3], // Track number size=2 - timeBytes[2], timeBytes[3], flags); // Timecode and flags - EbmlElement block = element(0xA1, // Block - TestUtil.joinByteArrays(blockBytes, data)); - EbmlElement referenceBlock = keyframe ? empty() : element(0xFB, (byte) 0x00); // ReferenceBlock - return element(0xA0, // BlockGroup - referenceBlock, - block); - } - - private static byte[] getIntegerBytes(int value) { - return TestUtil.createByteArray( - (value >> 24) & 0xFF, - (value >> 16) & 0xFF, - (value >> 8) & 0xFF, - (value) & 0xFF); - } - - private static byte[] getLongBytes(long value) { - byte[] result = new byte[8]; - for (int i = 0; i < 8; i++) { - result[7 - i] = (byte) ((value >> (8 * i)) & 0xFF); - } - return result; - } - - /** @see EbmlElement#EbmlElement(int, EbmlElement...) */ - private static EbmlElement element(int type, EbmlElement... childElements) { - return new EbmlElement(type, childElements); - } - - /** @see EbmlElement#EbmlElement(int, byte...) */ - private static EbmlElement element(int type, byte... payload) { - return new EbmlElement(type, payload); - } - - /** @see EbmlElement#EbmlElement() */ - private static EbmlElement empty() { - return new EbmlElement(); - } - - /** Represents an EBML element that can be serialized as a byte array. */ - private static final class EbmlElement { - - /** Returns a byte[] containing the concatenation of the data from all {@code elements}. */ - public static byte[] serialize(EbmlElement... elements) { - int size = 0; - for (EbmlElement element : elements) { - size += element.getSize(); - } - ByteBuffer buffer = ByteBuffer.allocate(size); - for (EbmlElement element : elements) { - element.getData(buffer); - } - return buffer.array(); - } - - private final int id; - private final EbmlElement[] childElements; - private final byte[] payload; - - /** Creates an element containing the specified {@code childElements}. */ - EbmlElement(int id, EbmlElement... childElements) { - this.id = id; - this.childElements = childElements; - payload = null; - } - - /** Creates an element containing the specified {@code payload}. */ - EbmlElement(int id, byte... payload) { - this.id = id; - this.payload = payload; - childElements = null; - } - - /** Creates a completely empty element that will contribute no bytes to the output. */ - EbmlElement() { - id = NO_VALUE; - payload = null; - childElements = null; - } - - private long getSize() { - if (id == NO_VALUE) { - return 0; - } - - long payloadSize = getPayloadSize(); - return getIdLength() + getVIntLength(payloadSize) + payloadSize; - } - - private long getPayloadSize() { - if (payload != null) { - return payload.length; - } - - int payloadSize = 0; - for (EbmlElement element : childElements) { - payloadSize += element.getSize(); - } - return payloadSize; - } - - private void getData(ByteBuffer byteBuffer) { - if (id == NO_VALUE) { - return; - } - - putId(byteBuffer); - putVInt(byteBuffer, getPayloadSize()); - if (payload != null) { - byteBuffer.put(payload); - } else { - for (EbmlElement atom : childElements) { - atom.getData(byteBuffer); - } - } - } - - private int getIdLength() { - if (id == NO_VALUE) { - return 0; - } - - for (int i = 0; i < 4; i++) { - if (id < 1 << (7 * i + 8)) { - return i + 1; - } - } - throw new IllegalArgumentException(); - } - - private static int getVIntLength(long vInt) { - for (int i = 1; i < 9; i++) { - if (vInt < 1 << (7 * i)) { - return i; - } - } - throw new IllegalArgumentException(); - } - - private void putId(ByteBuffer byteBuffer) { - int length = getIdLength(); - for (int i = length - 1; i >= 0; i--) { - byteBuffer.put((byte) ((id >> (i * 8)) & 0xFF)); - } - } - - private static void putVInt(ByteBuffer byteBuffer, long vInt) { - int vIntLength = getVIntLength(vInt); - vInt |= 1 << (vIntLength * 7); - for (int i = vIntLength - 1; i >= 0; i--) { - byteBuffer.put((byte) ((vInt >> (i * 8)) & 0xFF)); - } - } - - } - -} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/mp4/Mp4ExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/mp4/Mp4ExtractorTest.java index 820f73bc41..58ee872bfc 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/mp4/Mp4ExtractorTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/mp4/Mp4ExtractorTest.java @@ -15,488 +15,18 @@ */ package com.google.android.exoplayer.extractor.mp4; -import com.google.android.exoplayer.C; -import com.google.android.exoplayer.Format; import com.google.android.exoplayer.extractor.Extractor; -import com.google.android.exoplayer.extractor.SeekMap; -import com.google.android.exoplayer.testutil.FakeExtractorOutput; -import com.google.android.exoplayer.testutil.FakeTrackOutput; import com.google.android.exoplayer.testutil.TestUtil; -import com.google.android.exoplayer.util.MimeTypes; -import com.google.android.exoplayer.util.Util; import android.annotation.TargetApi; import android.test.InstrumentationTestCase; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - /** * Tests for {@link Mp4Extractor}. */ @TargetApi(16) public final class Mp4ExtractorTest extends InstrumentationTestCase { - /** String of hexadecimal bytes containing the video stsd payload from an AVC video. */ - private static final byte[] VIDEO_STSD_PAYLOAD = Util.getBytesFromHexString( - "00000000000000010000009961766331000000000000000100000000000000000000000000000000050002d00048" - + "000000480000000000000001000000000000000000000000000000000000000000000000000000000000000000" - + "18ffff0000002f617663430164001fffe100186764001facb402802dd80880000003008000001e078c19500100" - + "0468ee3cb000000014627472740000e35c0042a61000216cb8"); - private static final byte[] VIDEO_HDLR_PAYLOAD = Util.getBytesFromHexString( - "000000000000000076696465"); - private static final byte[] VIDEO_MDHD_PAYLOAD = Util.getBytesFromHexString( - "0000000000000000cf6c48890000001e00001c8a55c40000"); - private static final int TIMESCALE = 30; - private static final int VIDEO_WIDTH = 1280; - private static final int VIDEO_HEIGHT = 720; - - /** String of hexadecimal bytes containing the video stsd payload for an mp4v track. */ - private static final byte[] VIDEO_STSD_MP4V_PAYLOAD = Util.getBytesFromHexString( - "0000000000000001000000A36D703476000000000000000100000000000000000000000000000000014000B40048" - + "000000480000000000000001000000000000000000000000000000000000000000000000000000000000000000" - + "18FFFF0000004D6573647300000000033F00000004372011001A400004CF280002F1180528000001B001000001" - + "B58913000001000000012000C48D8800F50A04169463000001B2476F6F676C65060102"); - private static final int VIDEO_MP4V_WIDTH = 320; - private static final int VIDEO_MP4V_HEIGHT = 180; - - /** String of hexadecimal bytes containing the audio stsd payload from an AAC track. */ - private static final byte[] AUDIO_STSD_PAYLOAD = Util.getBytesFromHexString( - "0000000000000001000000596d703461000000000000000100000000000000000001001000000000ac4400000000" - + "003565736473000000000327000000041f401500023e00024bc000023280051012080000000000000000000000" - + "000000060102"); - private static final byte[] AUDIO_HDLR_PAYLOAD = Util.getBytesFromHexString( - "0000000000000000736f756e"); - private static final byte[] AUDIO_MDHD_PAYLOAD = Util.getBytesFromHexString( - "00000000cf6c4889cf6c488a0000ac4400a3e40055c40000"); - - /** String of hexadecimal bytes for an ftyp payload with major_brand mp41 and minor_version 0. **/ - private static final byte[] FTYP_PAYLOAD = Util.getBytesFromHexString("6d70343100000000"); - - /** String of hexadecimal bytes containing an mvhd payload from an AVC/AAC video. */ - private static final byte[] MVHD_PAYLOAD = Util.getBytesFromHexString( - "00000000cf6c4888cf6c48880000025800023ad40001000001000000000000000000000000010000000000000000" - + "000000000000000100000000000000000000000000004000000000000000000000000000000000000000000000" - + "000000000000000003"); - - /** String of hexadecimal bytes containing a tkhd payload with an unknown duration. */ - private static final byte[] TKHD_PAYLOAD = Util.getBytesFromHexString( - "00000007D1F0C7BFD1F0C7BF0000000000000000FFFFFFFF00000000000000000000000000000000000100000000" - + "0000000000000000000000010000000000000000000000000000400000000780000004380000"); - - /** Video frame timestamps in time units. */ - private static final int[] SAMPLE_TIMESTAMPS = {0, 2, 3, 5, 6, 7}; - /** Video frame sizes in bytes, including a very large sample. */ - private static final int[] SAMPLE_SIZES = {100, 20, 20, 44, 100, 1024 * 1024}; - /** Indices of key-frames. */ - private static final boolean[] SAMPLE_IS_SYNC = {true, false, false, false, true, true}; - /** Indices of video frame chunk offsets. */ - private static final int[] CHUNK_OFFSETS = {1208, 2128, 3128, 4128}; - /** Numbers of video frames in each chunk. */ - private static final int[] SAMPLES_IN_CHUNK = {2, 2, 1, 1}; - /** The mdat box must be large enough to avoid reading chunk sample data out of bounds. */ - private static final int MDAT_SIZE = 10 * 1024 * 1024; - /** Empty byte array. */ - private static final byte[] EMPTY = new byte[0]; - - public void testParsesValidMp4File() throws Exception { - FakeExtractorOutput extractorOutput = consumeTestData(true, false); - - // The seek map is correct. - assertSeekMap(extractorOutput.seekMap, true); - - // The video and audio formats are set correctly. - assertEquals(2, extractorOutput.trackOutputs.size()); - Format videoFormat = extractorOutput.trackOutputs.get(0).format; - Format audioFormat = extractorOutput.trackOutputs.get(1).format; - assertEquals(MimeTypes.VIDEO_H264, videoFormat.sampleMimeType); - assertEquals(VIDEO_WIDTH, videoFormat.width); - assertEquals(VIDEO_HEIGHT, videoFormat.height); - assertEquals(MimeTypes.AUDIO_AAC, audioFormat.sampleMimeType); - - // The timestamps and sizes are set correctly. - FakeTrackOutput videoTrackOutput = extractorOutput.trackOutputs.get(0); - videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length); - for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) { - byte[] sampleData = getOutputSampleData(i, true); - int sampleFlags = SAMPLE_IS_SYNC[i] ? C.BUFFER_FLAG_KEY_FRAME : 0; - long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]); - videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null); - } - } - - public void testParsesValidMp4FileWithoutStss() throws Exception { - FakeExtractorOutput extractorOutput = consumeTestData(false, false); - - // The seek map is correct. - assertSeekMap(extractorOutput.seekMap, false); - - // The timestamps and sizes are set correctly, and all samples are synchronization samples. - FakeTrackOutput videoTrackOutput = extractorOutput.trackOutputs.get(0); - videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length); - for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) { - byte[] sampleData = getOutputSampleData(i, true); - int sampleFlags = C.BUFFER_FLAG_KEY_FRAME; - long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]); - videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null); - } - } - - public void testParsesValidMp4vFile() throws Exception { - FakeExtractorOutput extractorOutput = consumeTestData(true, true); - - // The seek map is correct. - assertSeekMap(extractorOutput.seekMap, true); - - // The video and audio formats are set correctly. - assertEquals(2, extractorOutput.trackOutputs.size()); - Format videoFormat = extractorOutput.trackOutputs.get(0).format; - Format audioFormat = extractorOutput.trackOutputs.get(1).format; - assertEquals(MimeTypes.VIDEO_MP4V, videoFormat.sampleMimeType); - assertEquals(VIDEO_MP4V_WIDTH, videoFormat.width); - assertEquals(VIDEO_MP4V_HEIGHT, videoFormat.height); - assertEquals(MimeTypes.AUDIO_AAC, audioFormat.sampleMimeType); - - // The timestamps and sizes are set correctly. - FakeTrackOutput videoTrackOutput = extractorOutput.trackOutputs.get(0); - videoTrackOutput.assertSampleCount(SAMPLE_TIMESTAMPS.length); - for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) { - byte[] sampleData = getOutputSampleData(i, false); - int sampleFlags = SAMPLE_IS_SYNC[i] ? C.BUFFER_FLAG_KEY_FRAME : 0; - long sampleTimestampUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]); - videoTrackOutput.assertSample(i, sampleData, sampleTimestampUs, sampleFlags, null); - } - } - - private static void assertSeekMap(SeekMap seekMap, boolean haveStss) { - assertNotNull(seekMap); - int expectedSeekPosition = getSampleOffset(0); - for (int i = 0; i < SAMPLE_TIMESTAMPS.length; i++) { - // Seek to just before the current sample. - long seekPositionUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]) - 1; - assertEquals(expectedSeekPosition, seekMap.getPosition(seekPositionUs)); - // If the current sample is a sync sample, the expected seek position will change. - if (SAMPLE_IS_SYNC[i] || !haveStss) { - expectedSeekPosition = getSampleOffset(i); - } - // Seek to the current sample. - seekPositionUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]); - assertEquals(expectedSeekPosition, seekMap.getPosition(seekPositionUs)); - // Seek to just after the current sample. - seekPositionUs = getVideoTimestampUs(SAMPLE_TIMESTAMPS[i]) + 1; - assertEquals(expectedSeekPosition, seekMap.getPosition(seekPositionUs)); - } - } - - /** Returns a video timestamp in microseconds corresponding to {@code timeUnits}. */ - private static long getVideoTimestampUs(int timeUnits) { - return Util.scaleLargeTimestamp(timeUnits, C.MICROS_PER_SECOND, TIMESCALE); - } - - private static byte[] getStco() { - byte[] result = new byte[4 + 4 + 4 * CHUNK_OFFSETS.length]; - ByteBuffer buffer = ByteBuffer.wrap(result); - buffer.putInt(0); // Version (skipped) - buffer.putInt(CHUNK_OFFSETS.length); - for (int chunkOffset : CHUNK_OFFSETS) { - buffer.putInt(chunkOffset); - } - return result; - } - - private static byte[] getStsc() { - int samplesPerChunk = -1; - List samplesInChunkChangeIndices = new ArrayList<>(); - for (int i = 0; i < SAMPLES_IN_CHUNK.length; i++) { - if (SAMPLES_IN_CHUNK[i] != samplesPerChunk) { - samplesInChunkChangeIndices.add(i); - samplesPerChunk = SAMPLES_IN_CHUNK[i]; - } - } - - byte[] result = new byte[4 + 4 + 3 * 4 * samplesInChunkChangeIndices.size()]; - ByteBuffer buffer = ByteBuffer.wrap(result); - buffer.putInt(0); // Version (skipped) - buffer.putInt(samplesInChunkChangeIndices.size()); - for (int index : samplesInChunkChangeIndices) { - buffer.putInt(index + 1); - buffer.putInt(SAMPLES_IN_CHUNK[index]); - buffer.putInt(0); // Sample description index (skipped) - } - return result; - } - - private static byte[] getStsz() { - byte[] result = new byte[4 + 4 + 4 + 4 * SAMPLE_SIZES.length]; - ByteBuffer buffer = ByteBuffer.wrap(result); - buffer.putInt(0); // Version (skipped) - buffer.putInt(0); // No fixed sample size. - buffer.putInt(SAMPLE_SIZES.length); - for (int size : SAMPLE_SIZES) { - buffer.putInt(size); - } - return result; - } - - private static byte[] getStss() { - int synchronizationSampleCount = 0; - for (boolean sampleIsSync : SAMPLE_IS_SYNC) { - if (sampleIsSync) { - synchronizationSampleCount++; - } - } - byte[] result = new byte[4 + 4 + 4 * synchronizationSampleCount]; - ByteBuffer buffer = ByteBuffer.wrap(result); - buffer.putInt(0); // Version (skipped) - buffer.putInt(synchronizationSampleCount); - for (int i = 0; i < SAMPLE_IS_SYNC.length; i++) { - if (SAMPLE_IS_SYNC[i]) { - buffer.putInt(i + 1); - } - } - return result; - } - - private static byte[] getStts() { - int sampleTimestampDeltaChanges = 0; - int currentSampleTimestampDelta = -1; - for (int i = 1; i < SAMPLE_TIMESTAMPS.length; i++) { - int timestampDelta = SAMPLE_TIMESTAMPS[i] - SAMPLE_TIMESTAMPS[i - 1]; - if (timestampDelta != currentSampleTimestampDelta) { - sampleTimestampDeltaChanges++; - currentSampleTimestampDelta = timestampDelta; - } - } - - byte[] result = new byte[4 + 4 + 2 * 4 * sampleTimestampDeltaChanges]; - ByteBuffer buffer = ByteBuffer.wrap(result); - buffer.putInt(0); // Version (skipped); - buffer.putInt(sampleTimestampDeltaChanges); - int lastTimestampDeltaChangeIndex = 1; - currentSampleTimestampDelta = SAMPLE_TIMESTAMPS[1] - SAMPLE_TIMESTAMPS[0]; - for (int i = 2; i < SAMPLE_TIMESTAMPS.length; i++) { - int timestampDelta = SAMPLE_TIMESTAMPS[i] - SAMPLE_TIMESTAMPS[i - 1]; - if (timestampDelta != currentSampleTimestampDelta) { - buffer.putInt(i - lastTimestampDeltaChangeIndex); - lastTimestampDeltaChangeIndex = i; - buffer.putInt(currentSampleTimestampDelta); - currentSampleTimestampDelta = timestampDelta; - } - } - // The last sample also has a duration, so the number of entries is the number of samples. - buffer.putInt(SAMPLE_TIMESTAMPS.length - lastTimestampDeltaChangeIndex + 1); - buffer.putInt(currentSampleTimestampDelta); - return result; - } - - private static byte[] getMdat(int mdatOffset, boolean isH264) { - ByteBuffer mdat = ByteBuffer.allocate(MDAT_SIZE); - int sampleIndex = 0; - for (int chunk = 0; chunk < CHUNK_OFFSETS.length; chunk++) { - mdat.position(CHUNK_OFFSETS[chunk] - mdatOffset); - for (int sample = 0; sample < SAMPLES_IN_CHUNK[chunk]; sample++) { - mdat.put(getInputSampleData(sampleIndex++, isH264)); - } - } - return mdat.array(); - } - - private static byte[] getInputSampleData(int index, boolean isH264) { - ByteBuffer sample = ByteBuffer.allocate(SAMPLE_SIZES[index]); - for (int i = 0; i < SAMPLE_SIZES[index]; i++) { - sample.put((byte) i); - } - if (isH264) { - // First four bytes should specify the remaining length of the sample. This assumes that the - // sample consists of a single length delimited NAL unit. - sample.position(0); - sample.putInt(SAMPLE_SIZES[index] - 4); - } - return sample.array(); - } - - private static byte[] getOutputSampleData(int index, boolean isH264) { - byte[] sampleData = getInputSampleData(index, isH264); - if (isH264) { - // The output sample should begin with a NAL start code. - sampleData[0] = 0; - sampleData[1] = 0; - sampleData[2] = 0; - sampleData[3] = 1; - } - return sampleData; - } - - private static int getSampleOffset(int index) { - int sampleCount = 0; - int chunkIndex = 0; - int samplesLeftInChunk = SAMPLES_IN_CHUNK[chunkIndex]; - int offsetInChunk = 0; - while (sampleCount < index) { - offsetInChunk += SAMPLE_SIZES[sampleCount++]; - samplesLeftInChunk--; - if (samplesLeftInChunk == 0) { - chunkIndex++; - samplesLeftInChunk = SAMPLES_IN_CHUNK[chunkIndex]; - offsetInChunk = 0; - } - } - return CHUNK_OFFSETS[chunkIndex] + offsetInChunk; - } - - private static FakeExtractorOutput consumeTestData(boolean includeStss, boolean mp4vFormat) - throws IOException, InterruptedException { - byte[] testInputData = includeStss ? getTestMp4File(mp4vFormat) - : getTestMp4FileWithoutSynchronizationData(mp4vFormat); - return TestUtil.consumeTestData(new Mp4Extractor(), testInputData); - } - - /** Gets a valid MP4 file with audio/video tracks and synchronization data. */ - private static byte[] getTestMp4File(boolean mp4vFormat) { - return Mp4Atom.serialize( - atom(Atom.TYPE_ftyp, FTYP_PAYLOAD), - atom(Atom.TYPE_moov, - atom(Atom.TYPE_mvhd, MVHD_PAYLOAD), - atom(Atom.TYPE_trak, - atom(Atom.TYPE_tkhd, TKHD_PAYLOAD), - atom(Atom.TYPE_mdia, - atom(Atom.TYPE_mdhd, VIDEO_MDHD_PAYLOAD), - atom(Atom.TYPE_hdlr, VIDEO_HDLR_PAYLOAD), - atom(Atom.TYPE_minf, - atom(Atom.TYPE_vmhd, EMPTY), - atom(Atom.TYPE_stbl, - atom(Atom.TYPE_stsd, - mp4vFormat ? VIDEO_STSD_MP4V_PAYLOAD : VIDEO_STSD_PAYLOAD), - atom(Atom.TYPE_stts, getStts()), - atom(Atom.TYPE_stss, getStss()), - atom(Atom.TYPE_stsc, getStsc()), - atom(Atom.TYPE_stsz, getStsz()), - atom(Atom.TYPE_stco, getStco()))))), - atom(Atom.TYPE_trak, - atom(Atom.TYPE_tkhd, TKHD_PAYLOAD), - atom(Atom.TYPE_mdia, - atom(Atom.TYPE_mdhd, AUDIO_MDHD_PAYLOAD), - atom(Atom.TYPE_hdlr, AUDIO_HDLR_PAYLOAD), - atom(Atom.TYPE_minf, - atom(Atom.TYPE_vmhd, EMPTY), - atom(Atom.TYPE_stbl, - atom(Atom.TYPE_stsd, AUDIO_STSD_PAYLOAD), - atom(Atom.TYPE_stts, getStts()), - atom(Atom.TYPE_stss, getStss()), - atom(Atom.TYPE_stsc, getStsc()), - atom(Atom.TYPE_stsz, getStsz()), - atom(Atom.TYPE_stco, getStco())))))), - atom(Atom.TYPE_mdat, getMdat(mp4vFormat ? 1176 : 1166, !mp4vFormat))); - } - - /** Gets a valid MP4 file with audio/video tracks and without a synchronization table. */ - private static byte[] getTestMp4FileWithoutSynchronizationData(boolean mp4vFormat) { - return Mp4Atom.serialize( - atom(Atom.TYPE_ftyp, FTYP_PAYLOAD), - atom(Atom.TYPE_moov, - atom(Atom.TYPE_mvhd, MVHD_PAYLOAD), - atom(Atom.TYPE_trak, - atom(Atom.TYPE_tkhd, TKHD_PAYLOAD), - atom(Atom.TYPE_mdia, - atom(Atom.TYPE_mdhd, VIDEO_MDHD_PAYLOAD), - atom(Atom.TYPE_hdlr, VIDEO_HDLR_PAYLOAD), - atom(Atom.TYPE_minf, - atom(Atom.TYPE_vmhd, EMPTY), - atom(Atom.TYPE_stbl, - atom(Atom.TYPE_stsd, - mp4vFormat ? VIDEO_STSD_MP4V_PAYLOAD : VIDEO_STSD_PAYLOAD), - atom(Atom.TYPE_stts, getStts()), - atom(Atom.TYPE_stsc, getStsc()), - atom(Atom.TYPE_stsz, getStsz()), - atom(Atom.TYPE_stco, getStco()))))), - atom(Atom.TYPE_trak, - atom(Atom.TYPE_tkhd, TKHD_PAYLOAD), - atom(Atom.TYPE_mdia, - atom(Atom.TYPE_mdhd, AUDIO_MDHD_PAYLOAD), - atom(Atom.TYPE_hdlr, AUDIO_HDLR_PAYLOAD), - atom(Atom.TYPE_minf, - atom(Atom.TYPE_vmhd, EMPTY), - atom(Atom.TYPE_stbl, - atom(Atom.TYPE_stsd, AUDIO_STSD_PAYLOAD), - atom(Atom.TYPE_stts, getStts()), - atom(Atom.TYPE_stsc, getStsc()), - atom(Atom.TYPE_stsz, getStsz()), - atom(Atom.TYPE_stco, getStco())))))), - atom(Atom.TYPE_mdat, getMdat(mp4vFormat ? 1120 : 1110, !mp4vFormat))); - } - - private static Mp4Atom atom(int type, Mp4Atom... containedMp4Atoms) { - return new Mp4Atom(type, containedMp4Atoms); - } - - private static Mp4Atom atom(int type, byte[] payload) { - return new Mp4Atom(type, payload); - } - - /** - * MP4 atom that can be serialized as a byte array. - */ - private static final class Mp4Atom { - - public static byte[] serialize(Mp4Atom... atoms) { - int size = 0; - for (Mp4Atom atom : atoms) { - size += atom.getSize(); - } - ByteBuffer buffer = ByteBuffer.allocate(size); - for (Mp4Atom atom : atoms) { - atom.getData(buffer); - } - return buffer.array(); - } - - private static final int HEADER_SIZE = 8; - - private final int type; - private final Mp4Atom[] containedMp4Atoms; - private final byte[] payload; - - private Mp4Atom(int type, Mp4Atom... containedMp4Atoms) { - this.type = type; - this.containedMp4Atoms = containedMp4Atoms; - payload = null; - } - - private Mp4Atom(int type, byte[] payload) { - this.type = type; - this.payload = payload; - containedMp4Atoms = null; - } - - private int getSize() { - int size = HEADER_SIZE; - if (payload != null) { - size += payload.length; - } else { - for (Mp4Atom atom : containedMp4Atoms) { - size += atom.getSize(); - } - } - return size; - } - - private void getData(ByteBuffer byteBuffer) { - byteBuffer.putInt(getSize()); - byteBuffer.putInt(type); - - if (payload != null) { - byteBuffer.put(payload); - } else { - for (Mp4Atom atom : containedMp4Atoms) { - atom.getData(byteBuffer); - } - } - } - - } - public void testMp4Sample() throws Exception { TestUtil.assertOutput(new TestUtil.ExtractorFactory() { @Override diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggExtractorFileTests.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggExtractorFileTests.java deleted file mode 100644 index d4aca29f98..0000000000 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggExtractorFileTests.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer.extractor.ogg; - -import com.google.android.exoplayer.extractor.Extractor; -import com.google.android.exoplayer.testutil.TestUtil; -import com.google.android.exoplayer.testutil.TestUtil.ExtractorFactory; - -import android.test.InstrumentationTestCase; - -/** - * Unit test for {@link OpusReader}. - */ -public final class OggExtractorFileTests extends InstrumentationTestCase { - - private static final ExtractorFactory OGG_EXTRACTOR_FACTORY = new ExtractorFactory() { - @Override - public Extractor create() { - return new OggExtractor(); - } - }; - - public void testOpus() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear.opus", getInstrumentation()); - } - - public void testFlac() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac.ogg", getInstrumentation()); - } - - public void testFlacNoSeektable() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac_noseektable.ogg", - getInstrumentation()); - } - - public void testVorbis() throws Exception { - TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_vorbis.ogg", getInstrumentation()); - } - -} diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggExtractorTest.java index df119fb7e9..3b5cd47ae3 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggExtractorTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/OggExtractorTest.java @@ -15,24 +15,42 @@ */ package com.google.android.exoplayer.extractor.ogg; +import com.google.android.exoplayer.extractor.Extractor; import com.google.android.exoplayer.testutil.FakeExtractorInput; import com.google.android.exoplayer.testutil.TestUtil; +import com.google.android.exoplayer.testutil.TestUtil.ExtractorFactory; -import junit.framework.TestCase; +import android.test.InstrumentationTestCase; import java.io.IOException; /** * Unit test for {@link OggExtractor}. */ -public final class OggExtractorTest extends TestCase { +public final class OggExtractorTest extends InstrumentationTestCase { - private OggExtractor extractor; + private static final ExtractorFactory OGG_EXTRACTOR_FACTORY = new ExtractorFactory() { + @Override + public Extractor create() { + return new OggExtractor(); + } + }; - @Override - public void setUp() throws Exception { - super.setUp(); - extractor = new OggExtractor(); + public void testOpus() throws Exception { + TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear.opus", getInstrumentation()); + } + + public void testFlac() throws Exception { + TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac.ogg", getInstrumentation()); + } + + public void testFlacNoSeektable() throws Exception { + TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_flac_noseektable.ogg", + getInstrumentation()); + } + + public void testVorbis() throws Exception { + TestUtil.assertOutput(OGG_EXTRACTOR_FACTORY, "ogg/bear_vorbis.ogg", getInstrumentation()); } public void testSniffVorbis() throws Exception { @@ -80,7 +98,7 @@ public final class OggExtractorTest extends TestCase { FakeExtractorInput input = new FakeExtractorInput.Builder().setData(data) .setSimulateIOErrors(true).setSimulateUnknownLength(true).setSimulatePartialReads(true) .build(); - return TestUtil.sniffTestData(extractor, input); + return TestUtil.sniffTestData(OGG_EXTRACTOR_FACTORY.create(), input); } } diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisBitArrayTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisBitArrayTest.java index 17a0fd241e..b355140915 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisBitArrayTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisBitArrayTest.java @@ -15,7 +15,7 @@ */ package com.google.android.exoplayer.extractor.ogg; -import com.google.android.exoplayer.util.ParsableBitArray; +import com.google.android.exoplayer.testutil.TestUtil; import junit.framework.TestCase; @@ -25,9 +25,7 @@ import junit.framework.TestCase; public final class VorbisBitArrayTest extends TestCase { public void testReadBit() { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0x5c, 0x50 - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x5c, 0x50)); assertFalse(bitArray.readBit()); assertFalse(bitArray.readBit()); @@ -56,9 +54,7 @@ public final class VorbisBitArrayTest extends TestCase { } public void testSkipBits() { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xF0, 0x0F - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); bitArray.skipBits(10); assertEquals(10, bitArray.getPosition()); @@ -79,9 +75,7 @@ public final class VorbisBitArrayTest extends TestCase { public void testSkipBitsThrowsErrorIfEOB() { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xF0, 0x0F - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); try { bitArray.skipBits(17); @@ -90,9 +84,7 @@ public final class VorbisBitArrayTest extends TestCase { } public void testGetPosition() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xF0, 0x0F - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); assertEquals(0, bitArray.getPosition()); bitArray.readBit(); @@ -104,9 +96,7 @@ public final class VorbisBitArrayTest extends TestCase { } public void testSetPosition() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xF0, 0x0F - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); assertEquals(0, bitArray.getPosition()); bitArray.setPosition(4); @@ -121,9 +111,7 @@ public final class VorbisBitArrayTest extends TestCase { } public void testSetPositionIllegalPositions() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xF0, 0x0F - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F)); try { bitArray.setPosition(16); @@ -141,19 +129,14 @@ public final class VorbisBitArrayTest extends TestCase { } public void testReadInt32() { - byte[] data = {(byte) 0xF0, 0x0F, (byte) 0xF0, 0x0F}; - VorbisBitArray lsb = new VorbisBitArray(data); - assertEquals(0x0FF00FF0, lsb.readBits(32)); - - data = new byte[]{0x0F, (byte) 0xF0, 0x0F, (byte) 0xF0}; - lsb = new VorbisBitArray(data); - assertEquals(0xF00FF00F, lsb.readBits(32)); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xF0, 0x0F, 0xF0, 0x0F)); + assertEquals(0x0FF00FF0, bitArray.readBits(32)); + bitArray = new VorbisBitArray(TestUtil.createByteArray(0x0F, 0xF0, 0x0F, 0xF0)); + assertEquals(0xF00FF00F, bitArray.readBits(32)); } public void testReadBits() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0x03, 0x22 - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x03, 0x22)); assertEquals(3, bitArray.readBits(2)); bitArray.skipBits(6); @@ -166,18 +149,14 @@ public final class VorbisBitArrayTest extends TestCase { } public void testRead4BitsBeyondBoundary() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - 0x2e, 0x10 - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x2e, 0x10)); assertEquals(0x2e, bitArray.readBits(7)); assertEquals(7, bitArray.getPosition()); assertEquals(0x0, bitArray.readBits(4)); } public void testReadBitsBeyondByteBoundaries() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xFF, (byte) 0x0F, (byte) 0xFF, (byte) 0x0F - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xFF, 0x0F, 0xFF, 0x0F)); assertEquals(0x0FFF0FFF, bitArray.readBits(32)); @@ -202,9 +181,7 @@ public final class VorbisBitArrayTest extends TestCase { } public void testReadBitsIllegalLengths() throws Exception { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0x03, 0x22, 0x30 - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0x03, 0x22, 0x30)); // reading zero bits gets 0 without advancing position // (like a zero-bit read is defined to yield zer0) @@ -222,9 +199,7 @@ public final class VorbisBitArrayTest extends TestCase { } public void testLimit() { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xc0, 0x02 - }, 1); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xc0, 0x02), 1); try { bitArray.skipBits(9); @@ -240,7 +215,8 @@ public final class VorbisBitArrayTest extends TestCase { assertEquals(0, bitArray.getPosition()); } - bitArray.readBits(8); + int byteValue = bitArray.readBits(8); + assertEquals(0xc0, byteValue); assertEquals(8, bitArray.getPosition()); try { bitArray.readBit(); @@ -251,9 +227,8 @@ public final class VorbisBitArrayTest extends TestCase { } public void testBitsLeft() { - VorbisBitArray bitArray = new VorbisBitArray(new byte[]{ - (byte) 0xc0, 0x02 - }); + VorbisBitArray bitArray = new VorbisBitArray(TestUtil.createByteArray(0xc0, 0x02)); + assertEquals(16, bitArray.bitsLeft()); assertEquals(bitArray.limit(), bitArray.getPosition() + bitArray.bitsLeft()); @@ -293,44 +268,4 @@ public final class VorbisBitArrayTest extends TestCase { } } - public void testReadBitCompareWithMSb() { - byte[] data = {0x0F}; - VorbisBitArray lsb = new VorbisBitArray(data); - ParsableBitArray msb = new ParsableBitArray(data); - - assertEquals(lsb.readBit(), !msb.readBit()); - assertEquals(lsb.readBit(), !msb.readBit()); - assertEquals(lsb.readBit(), !msb.readBit()); - assertEquals(lsb.readBit(), !msb.readBit()); - assertEquals(lsb.readBit(), !msb.readBit()); - assertEquals(lsb.readBit(), !msb.readBit()); - assertEquals(lsb.readBit(), !msb.readBit()); - assertEquals(lsb.readBit(), !msb.readBit()); - } - - public void testReadBitsCompareWithMSb() { - byte[] data = {0x0F}; - VorbisBitArray lsb = new VorbisBitArray(data); - ParsableBitArray msb = new ParsableBitArray(data); - - assertEquals(15, lsb.readBits(4)); - assertEquals(lsb.readBits(4), msb.readBits(4)); - assertEquals(15, msb.readBits(4)); - } - - public void testReadBitsCompareWithMSbBeyondByteBoundary() { - byte[] data = {(byte) 0xF0, 0x0F}; - VorbisBitArray lsb = new VorbisBitArray(data); - ParsableBitArray msb = new ParsableBitArray(data); - - assertEquals(0x00, lsb.readBits(4)); - assertEquals(0x0F, msb.readBits(4)); - - assertEquals(0xFF, lsb.readBits(8)); - assertEquals(0x00, msb.readBits(8)); - - assertEquals(0x00, lsb.readBits(4)); - assertEquals(0x0F, msb.readBits(4)); - } - } diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisReaderTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisReaderTest.java index 00b08cc9c6..9d33944ad9 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisReaderTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisReaderTest.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer.extractor.ogg; +import com.google.android.exoplayer.extractor.ExtractorInput; import com.google.android.exoplayer.extractor.ogg.VorbisReader.VorbisSetup; import com.google.android.exoplayer.testutil.FakeExtractorInput; import com.google.android.exoplayer.testutil.FakeExtractorInput.SimulatedIOException; @@ -29,14 +30,6 @@ import java.io.IOException; */ public final class VorbisReaderTest extends TestCase { - private VorbisReader extractor; - - @Override - public void setUp() throws Exception { - super.setUp(); - extractor = new VorbisReader(); - } - public void testReadBits() throws Exception { assertEquals(0, VorbisReader.readBits((byte) 0x00, 2, 2)); assertEquals(1, VorbisReader.readBits((byte) 0x02, 1, 1)); @@ -57,7 +50,11 @@ public final class VorbisReaderTest extends TestCase { public void testReadSetupHeadersWithIOExceptions() throws IOException, InterruptedException { byte[] data = TestData.getVorbisHeaderPages(); - VorbisReader.VorbisSetup vorbisSetup = readSetupHeaders(createInput(data)); + ExtractorInput input = new FakeExtractorInput.Builder().setData(data).setSimulateIOErrors(true) + .setSimulateUnknownLength(true).setSimulatePartialReads(true).build(); + + VorbisReader reader = new VorbisReader(); + VorbisReader.VorbisSetup vorbisSetup = readSetupHeaders(reader, input); assertNotNull(vorbisSetup.idHeader); assertNotNull(vorbisSetup.commentHeader); @@ -88,12 +85,7 @@ public final class VorbisReaderTest extends TestCase { assertTrue(vorbisSetup.modes[1].blockFlag); } - private static FakeExtractorInput createInput(byte[] data) { - return new FakeExtractorInput.Builder().setData(data).setSimulateIOErrors(true) - .setSimulateUnknownLength(true).setSimulatePartialReads(true).build(); - } - - private VorbisSetup readSetupHeaders(FakeExtractorInput input) + private static VorbisSetup readSetupHeaders(VorbisReader reader, ExtractorInput input) throws IOException, InterruptedException { OggPacket oggPacket = new OggPacket(); while (true) { @@ -101,7 +93,7 @@ public final class VorbisReaderTest extends TestCase { if (!oggPacket.populate(input)) { fail(); } - VorbisSetup vorbisSetup = extractor.readSetupHeaders(oggPacket.getPayload()); + VorbisSetup vorbisSetup = reader.readSetupHeaders(oggPacket.getPayload()); if (vorbisSetup != null) { return vorbisSetup; } diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisUtilTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisUtilTest.java index 434cda6650..eca5f5ef25 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisUtilTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/ogg/VorbisUtilTest.java @@ -90,13 +90,13 @@ public final class VorbisUtilTest extends TestCase { public void testVerifyVorbisHeaderCapturePattern() throws ParserException { ParsableByteArray header = new ParsableByteArray( - new byte[]{0x01, 'v', 'o', 'r', 'b', 'i', 's'}); + new byte[] {0x01, 'v', 'o', 'r', 'b', 'i', 's'}); assertEquals(true, VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, header, false)); } public void testVerifyVorbisHeaderCapturePatternInvalidHeader() { ParsableByteArray header = new ParsableByteArray( - new byte[]{0x01, 'v', 'o', 'r', 'b', 'i', 's'}); + new byte[] {0x01, 'v', 'o', 'r', 'b', 'i', 's'}); try { VorbisUtil.verifyVorbisHeaderCapturePattern(0x99, header, false); fail(); @@ -107,13 +107,13 @@ public final class VorbisUtilTest extends TestCase { public void testVerifyVorbisHeaderCapturePatternInvalidHeaderQuite() throws ParserException { ParsableByteArray header = new ParsableByteArray( - new byte[]{0x01, 'v', 'o', 'r', 'b', 'i', 's'}); + new byte[] {0x01, 'v', 'o', 'r', 'b', 'i', 's'}); assertFalse(VorbisUtil.verifyVorbisHeaderCapturePattern(0x99, header, true)); } public void testVerifyVorbisHeaderCapturePatternInvalidPattern() { ParsableByteArray header = new ParsableByteArray( - new byte[]{0x01, 'x', 'v', 'o', 'r', 'b', 'i', 's'}); + new byte[] {0x01, 'x', 'v', 'o', 'r', 'b', 'i', 's'}); try { VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, header, false); fail(); @@ -125,7 +125,7 @@ public final class VorbisUtilTest extends TestCase { public void testVerifyVorbisHeaderCapturePatternQuiteInvalidPatternQuite() throws ParserException { ParsableByteArray header = new ParsableByteArray( - new byte[]{0x01, 'x', 'v', 'o', 'r', 'b', 'i', 's'}); + new byte[] {0x01, 'x', 'v', 'o', 'r', 'b', 'i', 's'}); assertFalse(VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, header, true)); }