Support multi-track in MKV/WebM extractor.

Issue: #514
This commit is contained in:
Oliver Woodman 2015-09-01 14:01:43 +01:00
parent e07c35815e
commit 10badcc430
3 changed files with 158 additions and 160 deletions

View file

@ -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(),

View file

@ -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);

View file

@ -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<Track> 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();
}