From 10badcc43050e3e39a3ca6df860ca690265c14b1 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Tue, 1 Sep 2015 14:01:43 +0100 Subject: [PATCH] Support multi-track in MKV/WebM extractor. Issue: #514 --- .../extractor/webm/StreamBuilder.java | 50 ++-- .../extractor/webm/WebmExtractorTest.java | 222 +++++++++--------- .../extractor/webm/WebmExtractor.java | 46 ++-- 3 files changed, 158 insertions(+), 160 deletions(-) diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/StreamBuilder.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/StreamBuilder.java index e644cc0624..f50bb6a2f9 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/StreamBuilder.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/StreamBuilder.java @@ -91,41 +91,44 @@ import java.util.List; return this; } - public StreamBuilder addVp9Track(int width, int height, + public StreamBuilder addVp9Track(byte trackNumber, int width, int height, ContentEncodingSettings contentEncodingSettings) { - trackEntries.add(createVideoTrackEntry("V_VP9", width, height, contentEncodingSettings, null)); + trackEntries.add(createVideoTrackEntry(trackNumber, "V_VP9", width, height, + contentEncodingSettings, null)); return this; } - public StreamBuilder addH264Track(int width, int height, byte[] codecPrivate) { - trackEntries.add(createVideoTrackEntry("V_MPEG4/ISO/AVC", width, height, null, codecPrivate)); + 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(int channelCount, int sampleRate, int codecDelay, - int seekPreRoll, byte[] codecPrivate) { - trackEntries.add(createAudioTrackEntry("A_OPUS", channelCount, sampleRate, codecPrivate, - codecDelay, seekPreRoll, NO_VALUE)); + 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(int channelCount, int sampleRate, int codecDelay, - int seekPreRoll, byte[] codecPrivate, int defaultDurationNs) { - trackEntries.add(createAudioTrackEntry("A_OPUS", channelCount, sampleRate, codecPrivate, - codecDelay, seekPreRoll, defaultDurationNs)); + 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(int channelCount, int sampleRate, byte[] codecPrivate) { - trackEntries.add(createAudioTrackEntry("A_VORBIS", channelCount, sampleRate, codecPrivate, - NO_VALUE, NO_VALUE, NO_VALUE)); + 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() { + public StreamBuilder addUnsupportedTrack(byte trackNumber) { trackEntries.add(element(0xAE, // TrackEntry element(0x86, "D_WEBVTT/metadata".getBytes()), // CodecID - element(0xD7, (byte) 0x03), // TrackNumber + element(0xD7, trackNumber), // TrackNumber element(0x83, (byte) 0x11))); // TrackType return this; } @@ -252,8 +255,8 @@ import java.util.List; durationFirst ? timescaleElement : durationElement); } - private static EbmlElement createVideoTrackEntry(String codecId, int pixelWidth, int pixelHeight, - ContentEncodingSettings contentEncodingSettings, byte[] codecPrivate) { + 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; @@ -297,7 +300,7 @@ import java.util.List; return element(0xAE, // TrackEntry element(0x86, codecId.getBytes()), // CodecID - element(0xD7, (byte) 0x01), // TrackNumber + element(0xD7, trackNumber), // TrackNumber element(0x83, (byte) 0x01), // TrackType contentEncodingSettingsElement, element(0xE0, // Video @@ -306,13 +309,14 @@ import java.util.List; codecPrivateElement); } - private static EbmlElement createAudioTrackEntry(String codecId, int channelCount, int sampleRate, - byte[] codecPrivate, int codecDelay, int seekPreRoll, int defaultDurationNs) { + 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, (byte) 0x02), // TrackNumber + element(0xD7, trackNumber), // TrackNumber element(0x83, (byte) 0x02), // TrackType // CodecDelay codecDelay != NO_VALUE ? element(0x56AA, getIntegerBytes(codecDelay)) : empty(), diff --git a/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/WebmExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/WebmExtractorTest.java index 898c282a83..e463a17e82 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/WebmExtractorTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer/extractor/webm/WebmExtractorTest.java @@ -60,6 +60,11 @@ public final class WebmExtractorTest extends InstrumentationTestCase { 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 UUID ZERO_UUID = new UUID(0, 0); @@ -86,13 +91,13 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .build(1); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -100,7 +105,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .build(1); TestUtil.consumeTestData(extractor, data); @@ -108,7 +113,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -116,14 +121,14 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, + .addOpusTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) .build(1); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -131,13 +136,14 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVorbisTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, getVorbisCodecPrivate()) + .addVorbisTrack(AUDIO_TRACK_NUMBER, TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, + getVorbisCodecPrivate()) .build(1); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_VORBIS); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_VORBIS); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -145,13 +151,13 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(MATROSKA_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addH264Track(TEST_WIDTH, TEST_HEIGHT, TEST_H264_CODEC_PRIVATE) + .addH264Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, TEST_H264_CODEC_PRIVATE) .build(1); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertH264VideoFormat(DEFAULT_TIMECODE_SCALE); + assertH264VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -159,8 +165,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, + .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); @@ -168,8 +174,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { assertTracksEnded(); assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -177,9 +183,9 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) - .addUnsupportedTrack() - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, + .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); @@ -188,8 +194,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { assertTracksEnded(); // Even though the input stream has 3 tracks, only 2 of them are supported and will be reported. assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -197,21 +203,22 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) - .addVorbisTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, getVorbisCodecPrivate()) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, - TEST_SEEK_PRE_ROLL, TEST_OPUS_CODEC_PRIVATE) + .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); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - // Even though the input stream has 4 supported tracks, only the first video and audio track - // will be reported. - assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_VORBIS); + assertEquals(4, extractorOutput.numberOfTracks); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_VORBIS); + assertVp9VideoFormat(SECOND_VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertAudioFormat(SECOND_AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); assertIndex(DEFAULT_TIMECODE_SCALE, 1); } @@ -220,13 +227,13 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .build(1); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); assertIndex(DEFAULT_TIMECODE_SCALE, 1); DrmInitData drmInitData = extractorOutput.drmInitData; assertNotNull(drmInitData); @@ -238,13 +245,13 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .build(3); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); assertIndex(DEFAULT_TIMECODE_SCALE, 3); } @@ -268,13 +275,13 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(timecodeScale, TEST_DURATION_TIMECODE, omitTimecodeScaleIfDefault, afterDuration) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .build(3); TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(timecodeScale); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, timecodeScale); assertIndex(timecodeScale, 3); } @@ -283,7 +290,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, media) .build(0); @@ -298,7 +305,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .build(1); TestUtil.consumeTestData(extractor, data); @@ -310,7 +317,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(MATROSKA_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .build(1); TestUtil.consumeTestData(extractor, data); @@ -322,7 +329,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader("webB") .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .build(1); try { TestUtil.consumeTestData(extractor, data); @@ -337,7 +344,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .build(1); try { TestUtil.consumeTestData(extractor, data); @@ -352,7 +359,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .build(1); try { TestUtil.consumeTestData(extractor, data); @@ -368,7 +375,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .build(1); try { TestUtil.consumeTestData(extractor, data); @@ -383,7 +390,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .build(1); try { TestUtil.consumeTestData(extractor, data); @@ -398,7 +405,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .build(1); try { TestUtil.consumeTestData(extractor, data); @@ -413,7 +420,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, media) .build(1); @@ -421,8 +428,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertSample(0, media, 0, true, false, null, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertSample(0, media, 0, true, false, null, getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadSampleKeyframeStripped() throws IOException, InterruptedException { @@ -433,7 +440,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, sampleBytes) .build(1); @@ -441,8 +448,9 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertSample(0, unstrippedSampleBytes, 0, true, false, null, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertSample(0, unstrippedSampleBytes, 0, true, false, null, + getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadSampleKeyframeManyBytesStripped() throws IOException, InterruptedException { @@ -453,7 +461,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .addSimpleBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, sampleBytes) .build(1); @@ -461,8 +469,9 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertSample(0, unstrippedSampleBytes, 0, true, false, null, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertSample(0, unstrippedSampleBytes, 0, true, false, null, + getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadTwoTrackSamples() throws IOException, InterruptedException { @@ -470,8 +479,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, + .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) @@ -483,10 +492,10 @@ public final class WebmExtractorTest extends InstrumentationTestCase { assertTracksEnded(); assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); - assertSample(0, media, 0, true, false, null, getVideoOutput()); - assertSample(0, media, 0, true, false, null, getAudioOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertSample(0, media, 0, true, false, null, getTrackOutput(VIDEO_TRACK_NUMBER)); + assertSample(0, media, 0, true, false, null, getTrackOutput(AUDIO_TRACK_NUMBER)); } public void testReadTwoTrackSamplesWithSkippedTrack() throws IOException, InterruptedException { @@ -494,9 +503,9 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addUnsupportedTrack() - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, + .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) @@ -510,10 +519,10 @@ public final class WebmExtractorTest extends InstrumentationTestCase { assertTracksEnded(); assertEquals(2, extractorOutput.numberOfTracks); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); - assertSample(0, media, 0, true, false, null, getVideoOutput()); - assertSample(0, media, 0, true, false, null, getAudioOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertSample(0, media, 0, true, false, null, getTrackOutput(VIDEO_TRACK_NUMBER)); + assertSample(0, media, 0, true, false, null, getTrackOutput(AUDIO_TRACK_NUMBER)); } public void testReadBlock() throws IOException, InterruptedException { @@ -521,7 +530,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, + .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) @@ -530,8 +539,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); - assertSample(0, media, 0, true, false, null, getAudioOutput()); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertSample(0, media, 0, true, false, null, getTrackOutput(AUDIO_TRACK_NUMBER)); } public void testReadBlockNonKeyframe() throws IOException, InterruptedException { @@ -539,7 +548,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .addBlockMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, false /* keyframe */, false /* invisible */, media) .build(1); @@ -547,8 +556,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertSample(0, media, 0, false, false, null, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertSample(0, media, 0, false, false, null, getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadEncryptedFrame() throws IOException, InterruptedException { @@ -557,7 +566,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, true /* validSignalByte */, media) @@ -566,8 +575,9 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertSample(0, media, 0, true, false, TEST_ENCRYPTION_KEY_ID, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertSample(0, media, 0, true, false, TEST_ENCRYPTION_KEY_ID, + getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadEncryptedFrameWithInvalidSignalByte() @@ -577,7 +587,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, settings) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, settings) .addSimpleBlockEncryptedMedia(1 /* trackNumber */, 0 /* clusterTimecode */, 0 /* blockTimecode */, true /* keyframe */, false /* invisible */, false /* validSignalByte */, media) @@ -597,7 +607,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */, false /* keyframe */, true /* invisible */, media) .build(1); @@ -605,8 +615,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertSample(0, media, 25000, false, true, null, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertSample(0, media, 25000, false, true, null, getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadSampleCustomTimecodeScale() throws IOException, InterruptedException { @@ -615,7 +625,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(timecodeScale, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .addSimpleBlockMedia(1 /* trackNumber */, 12 /* clusterTimecode */, 13 /* blockTimecode */, false /* keyframe */, false /* invisible */, media) .build(1); @@ -623,8 +633,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(timecodeScale); - assertSample(0, media, 25, false, false, null, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, timecodeScale); + assertSample(0, media, 25, false, false, null, getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadSampleNegativeSimpleBlockTimecode() throws IOException, InterruptedException { @@ -632,7 +642,7 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addVp9Track(TEST_WIDTH, TEST_HEIGHT, null) + .addVp9Track(VIDEO_TRACK_NUMBER, TEST_WIDTH, TEST_HEIGHT, null) .addSimpleBlockMedia(1 /* trackNumber */, 13 /* clusterTimecode */, -12 /* blockTimecode */, true /* keyframe */, true /* invisible */, media) .build(1); @@ -640,8 +650,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertVp9VideoFormat(DEFAULT_TIMECODE_SCALE); - assertSample(0, media, 1000, true, true, null, getVideoOutput()); + assertVp9VideoFormat(VIDEO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE); + assertSample(0, media, 1000, true, true, null, getTrackOutput(VIDEO_TRACK_NUMBER)); } public void testReadSampleWithFixedSizeLacing() throws IOException, InterruptedException { @@ -649,8 +659,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL, - TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS) + .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, media) .build(1); @@ -658,11 +668,11 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, 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, getAudioOutput()); + null, getTrackOutput(AUDIO_TRACK_NUMBER)); } } @@ -671,8 +681,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { byte[] data = new StreamBuilder() .setHeader(WEBM_DOC_TYPE) .setInfo(DEFAULT_TIMECODE_SCALE, TEST_DURATION_TIMECODE) - .addOpusTrack(TEST_CHANNEL_COUNT, TEST_SAMPLE_RATE, TEST_CODEC_DELAY, TEST_SEEK_PRE_ROLL, - TEST_OPUS_CODEC_PRIVATE, TEST_DEFAULT_DURATION_NS) + .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); @@ -680,31 +690,25 @@ public final class WebmExtractorTest extends InstrumentationTestCase { TestUtil.consumeTestData(extractor, data); assertTracksEnded(); - assertAudioFormat(DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); + assertAudioFormat(AUDIO_TRACK_NUMBER, DEFAULT_TIMECODE_SCALE, MimeTypes.AUDIO_OPUS); assertSample(0, Arrays.copyOfRange(media, 0, 256), 0 * TEST_DEFAULT_DURATION_NS / 1000, true, - false, null, getAudioOutput()); + false, null, getTrackOutput(AUDIO_TRACK_NUMBER)); assertSample(1, Arrays.copyOfRange(media, 256, 257), 1 * TEST_DEFAULT_DURATION_NS / 1000, true, - false, null, getAudioOutput()); + false, null, getTrackOutput(AUDIO_TRACK_NUMBER)); assertSample(2, Arrays.copyOfRange(media, 257, 300), 2 * TEST_DEFAULT_DURATION_NS / 1000, true, - false, null, getAudioOutput()); + false, null, getTrackOutput(AUDIO_TRACK_NUMBER)); } - private FakeTrackOutput getVideoOutput() { - // In the sample data the video track has id 1. - return extractorOutput.trackOutputs.get(1); - } - - private FakeTrackOutput getAudioOutput() { - // In the sample data the video track has id 2. - return extractorOutput.trackOutputs.get(2); + private FakeTrackOutput getTrackOutput(int trackNumber) { + return extractorOutput.trackOutputs.get(trackNumber); } private void assertTracksEnded() { assertTrue(extractorOutput.tracksEnded); } - private void assertVp9VideoFormat(int timecodeScale) { - MediaFormat format = getVideoOutput().format; + private void assertVp9VideoFormat(int trackNumber, int timecodeScale) { + MediaFormat format = getTrackOutput(trackNumber).format; assertEquals(Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000), format.durationUs); assertEquals(TEST_WIDTH, format.width); @@ -712,8 +716,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { assertEquals(MimeTypes.VIDEO_VP9, format.mimeType); } - private void assertH264VideoFormat(int timecodeScale) { - MediaFormat format = getVideoOutput().format; + private void assertH264VideoFormat(int trackNumber, int timecodeScale) { + MediaFormat format = getTrackOutput(trackNumber).format; assertEquals(Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000), format.durationUs); assertEquals(TEST_WIDTH, format.width); @@ -721,8 +725,8 @@ public final class WebmExtractorTest extends InstrumentationTestCase { assertEquals(MimeTypes.VIDEO_H264, format.mimeType); } - private void assertAudioFormat(int timecodeScale, String expectedMimeType) { - MediaFormat format = getAudioOutput().format; + private void assertAudioFormat(int trackNumber, int timecodeScale, String expectedMimeType) { + MediaFormat format = getTrackOutput(trackNumber).format; assertEquals(Util.scaleLargeTimestamp(TEST_DURATION_TIMECODE, timecodeScale, 1000), format.durationUs); assertEquals(TEST_CHANNEL_COUNT, format.channelCount); diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java index 561971995d..552a04b612 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer.util.ParsableByteArray; import com.google.android.exoplayer.util.Util; import android.util.Pair; +import android.util.SparseArray; import java.io.IOException; import java.nio.ByteBuffer; @@ -81,7 +82,6 @@ public final class WebmExtractor implements Extractor { private static final int MP3_MAX_INPUT_SIZE = 4096; private static final int ENCRYPTION_IV_SIZE = 8; private static final int TRACK_TYPE_AUDIO = 2; - private static final int TRACK_TYPE_VIDEO = 1; private static final int UNKNOWN = -1; private static final int ID_EBML = 0x1A45DFA3; @@ -143,6 +143,7 @@ public final class WebmExtractor implements Extractor { private final EbmlReader reader; private final VarintReader varintReader; + private final SparseArray tracks; // Temporary arrays. private final ParsableByteArray nalStartCode; @@ -158,10 +159,10 @@ public final class WebmExtractor implements Extractor { private long durationTimecode = C.UNKNOWN_TIME_US; private long durationUs = C.UNKNOWN_TIME_US; + // The track corresponding to the current TrackEntry element, or null. private Track currentTrack; - private Track audioTrack; - private Track videoTrack; + // Whether drm init data has been sent to the output. private boolean sentDrmInitData; // Master seek entry related elements. @@ -208,6 +209,7 @@ public final class WebmExtractor implements Extractor { this.reader = reader; this.reader.init(new InnerEbmlReaderOutput()); varintReader = new VarintReader(); + tracks = new SparseArray<>(); scratch = new ParsableByteArray(4); vorbisNumPageSamples = new ParsableByteArray(ByteBuffer.allocate(4).putInt(-1).array()); seekEntryIdBytes = new ParsableByteArray(4); @@ -399,8 +401,7 @@ public final class WebmExtractor implements Extractor { if (!sampleSeenReferenceBlock) { blockFlags |= C.SAMPLE_FLAG_SYNC; } - outputSampleMetadata((audioTrack != null && blockTrackNumber == audioTrack.number) - ? audioTrack.output : videoTrack.output, blockTimeUs); + outputSampleMetadata(tracks.get(blockTrackNumber), blockTimeUs); blockState = BLOCK_STATE_START; return; case ID_CONTENT_ENCODING: @@ -421,26 +422,16 @@ public final class WebmExtractor implements Extractor { } return; case ID_TRACK_ENTRY: - if ((currentTrack.type == TRACK_TYPE_AUDIO && audioTrack != null) - || (currentTrack.type == TRACK_TYPE_VIDEO && videoTrack != null)) { - // There is more than 1 audio/video track. Ignore everything but the first. - currentTrack = null; - return; - } - if (currentTrack.type == TRACK_TYPE_AUDIO && isCodecSupported(currentTrack.codecId)) { - audioTrack = currentTrack; - audioTrack.initializeOutput(extractorOutput, durationUs); - } else if (currentTrack.type == TRACK_TYPE_VIDEO - && isCodecSupported(currentTrack.codecId)) { - videoTrack = currentTrack; - videoTrack.initializeOutput(extractorOutput, durationUs); + if (tracks.get(currentTrack.number) == null && isCodecSupported(currentTrack.codecId)) { + currentTrack.initializeOutput(extractorOutput, durationUs); + tracks.put(currentTrack.number, currentTrack); } else { - // Unsupported track type. Do nothing. + // We've seen this track entry before, or the codec is unsupported. Do nothing. } currentTrack = null; return; case ID_TRACKS: - if (videoTrack == null && audioTrack == null) { + if (tracks.size() == 0) { throw new ParserException("No valid tracks were found"); } extractorOutput.endTracks(); @@ -614,16 +605,15 @@ public final class WebmExtractor implements Extractor { scratch.reset(); } - // Ignore the block if the track number equals neither the audio track nor the video track. - if ((audioTrack == null || audioTrack.number != blockTrackNumber) - && (videoTrack == null || videoTrack.number != blockTrackNumber)) { + Track track = tracks.get(blockTrackNumber); + + // Ignore the block if we don't know about the track to which it belongs. + if (track == null) { input.skipFully(contentSize - blockTrackNumberLength); blockState = BLOCK_STATE_START; return; } - Track track = (audioTrack != null && blockTrackNumber == audioTrack.number) - ? audioTrack : videoTrack; if (blockState == BLOCK_STATE_HEADER) { // Read the relative timecode (2 bytes) and flags (1 byte). readScratch(input, 3); @@ -723,7 +713,7 @@ public final class WebmExtractor implements Extractor { writeSampleData(input, track, blockLacingSampleSizes[blockLacingSampleIndex]); long sampleTimeUs = this.blockTimeUs + (blockLacingSampleIndex * track.defaultSampleDurationNs) / 1000; - outputSampleMetadata(track.output, sampleTimeUs); + outputSampleMetadata(track, sampleTimeUs); blockLacingSampleIndex++; } blockState = BLOCK_STATE_START; @@ -739,8 +729,8 @@ public final class WebmExtractor implements Extractor { } } - private void outputSampleMetadata(TrackOutput trackOutput, long timeUs) { - trackOutput.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, blockEncryptionKeyId); + private void outputSampleMetadata(Track track, long timeUs) { + track.output.sampleMetadata(timeUs, blockFlags, sampleBytesWritten, 0, blockEncryptionKeyId); sampleRead = true; resetSample(); }