mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
webm_extractor_tests: Add tests for multi track Webm Extractor Support
Refactor the extractor tests to enable testing of multi track Webm support. Github Issue: #363
This commit is contained in:
parent
48fc9635a9
commit
9b6c30525e
1 changed files with 259 additions and 112 deletions
|
|
@ -70,55 +70,105 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
private static final int ID_VP9 = 0;
|
private static final int ID_VP9 = 0;
|
||||||
private static final int ID_OPUS = 1;
|
private static final int ID_OPUS = 1;
|
||||||
private static final int ID_VORBIS = 2;
|
private static final int ID_VORBIS = 2;
|
||||||
|
private static final int ID_DUMMY = 3;
|
||||||
|
|
||||||
private WebmExtractor extractor;
|
private WebmExtractor extractor;
|
||||||
private TestOutput output;
|
private TestExtractorOutput extractorOutput;
|
||||||
|
private TestTrackOutput audioOutput;
|
||||||
|
private TestTrackOutput videoOutput;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
extractor = new WebmExtractor();
|
extractor = new WebmExtractor();
|
||||||
output = new TestOutput();
|
extractorOutput = new TestExtractorOutput();
|
||||||
extractor.init(output);
|
audioOutput = new TestTrackOutput();
|
||||||
|
videoOutput = new TestTrackOutput();
|
||||||
|
extractor.init(extractorOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
extractor = null;
|
extractor = null;
|
||||||
output = null;
|
extractorOutput = null;
|
||||||
|
audioOutput = null;
|
||||||
|
videoOutput = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadInitializationSegment() throws IOException, InterruptedException {
|
public void testReadInitializationSegment() throws IOException, InterruptedException {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, null));
|
consume(
|
||||||
assertFormat();
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, null));
|
||||||
|
assertVideoFormat();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareOpus() throws IOException, InterruptedException {
|
public void testPrepareOpus() throws IOException, InterruptedException {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_OPUS, null));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_OPUS}, null));
|
||||||
assertAudioFormat(ID_OPUS);
|
assertAudioFormat(ID_OPUS);
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareVorbis() throws IOException, InterruptedException {
|
public void testPrepareVorbis() throws IOException, InterruptedException {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VORBIS, null));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VORBIS}, null));
|
||||||
|
assertAudioFormat(ID_VORBIS);
|
||||||
|
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPrepareTwoTracks() throws IOException, InterruptedException {
|
||||||
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9, ID_OPUS}, null));
|
||||||
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
|
assertVideoFormat();
|
||||||
|
assertAudioFormat(ID_OPUS);
|
||||||
|
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPrepareThreeTracks() throws IOException, InterruptedException {
|
||||||
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9, ID_DUMMY, ID_OPUS}, null));
|
||||||
|
// Eventhough the input stream has 3 tracks, only 2 of them are supported and will be reported.
|
||||||
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
|
assertVideoFormat();
|
||||||
|
assertAudioFormat(ID_OPUS);
|
||||||
|
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPrepareFourTracks() throws IOException, InterruptedException {
|
||||||
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9, ID_VORBIS, ID_VP9, ID_OPUS}, null));
|
||||||
|
// Eventhough the input stream has 4 supported tracks, only the first video and audio track will
|
||||||
|
// be reported.
|
||||||
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
|
assertVideoFormat();
|
||||||
assertAudioFormat(ID_VORBIS);
|
assertAudioFormat(ID_VORBIS);
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareContentEncodingEncryption() throws IOException, InterruptedException {
|
public void testPrepareContentEncodingEncryption() throws IOException, InterruptedException {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 1);
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings));
|
consume(
|
||||||
assertFormat();
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings));
|
||||||
|
assertVideoFormat();
|
||||||
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
assertIndex(new IndexPoint(0, 0, TEST_DURATION_US));
|
||||||
DrmInitData drmInitData = output.drmInitData;
|
DrmInitData drmInitData = extractorOutput.drmInitData;
|
||||||
assertNotNull(output.drmInitData);
|
assertNotNull(drmInitData);
|
||||||
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, drmInitData.get(WIDEVINE_UUID));
|
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, drmInitData.get(WIDEVINE_UUID));
|
||||||
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, drmInitData.get(ZERO_UUID));
|
android.test.MoreAsserts.assertEquals(TEST_ENCRYPTION_KEY_ID, drmInitData.get(ZERO_UUID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareThreeCuePoints() throws IOException, InterruptedException {
|
public void testPrepareThreeCuePoints() throws IOException, InterruptedException {
|
||||||
consume(createInitializationSegment(3, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, null));
|
consume(
|
||||||
assertFormat();
|
createInitializationSegment(3, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, null));
|
||||||
|
assertVideoFormat();
|
||||||
assertIndex(
|
assertIndex(
|
||||||
new IndexPoint(0, 0, 10000),
|
new IndexPoint(0, 0, 10000),
|
||||||
new IndexPoint(10000, 0, 10000),
|
new IndexPoint(10000, 0, 10000),
|
||||||
|
|
@ -126,8 +176,8 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrepareCustomTimecodeScale() throws IOException, InterruptedException {
|
public void testPrepareCustomTimecodeScale() throws IOException, InterruptedException {
|
||||||
consume(createInitializationSegment(3, 0, true, 1000, ID_VP9, null));
|
consume(createInitializationSegment(3, 0, true, 1000, new int[] {ID_VP9}, null));
|
||||||
assertFormat();
|
assertVideoFormat();
|
||||||
assertIndex(
|
assertIndex(
|
||||||
new IndexPoint(0, 0, 10),
|
new IndexPoint(0, 0, 10),
|
||||||
new IndexPoint(10, 0, 10),
|
new IndexPoint(10, 0, 10),
|
||||||
|
|
@ -136,7 +186,9 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
public void testPrepareNoCuePoints() throws IOException, InterruptedException {
|
public void testPrepareNoCuePoints() throws IOException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
consume(createInitializationSegment(0, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, null));
|
consume(
|
||||||
|
createInitializationSegment(0, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, null));
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
assertEquals("Invalid/missing cue points", exception.getMessage());
|
assertEquals("Invalid/missing cue points", exception.getMessage());
|
||||||
|
|
@ -145,7 +197,9 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
public void testPrepareInvalidDocType() throws IOException, InterruptedException {
|
public void testPrepareInvalidDocType() throws IOException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
consume(createInitializationSegment(1, 0, false, DEFAULT_TIMECODE_SCALE, ID_VP9, null));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, false, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, null));
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
assertEquals("DocType webB not supported", exception.getMessage());
|
assertEquals("DocType webB not supported", exception.getMessage());
|
||||||
|
|
@ -155,7 +209,9 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
public void testPrepareInvalidContentEncodingOrder() throws IOException, InterruptedException {
|
public void testPrepareInvalidContentEncodingOrder() throws IOException, InterruptedException {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(1, 1, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(1, 1, 1, 5, 1);
|
||||||
try {
|
try {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings));
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
assertEquals("ContentEncodingOrder 1 not supported", exception.getMessage());
|
assertEquals("ContentEncodingOrder 1 not supported", exception.getMessage());
|
||||||
|
|
@ -165,7 +221,9 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
public void testPrepareInvalidContentEncodingScope() throws IOException, InterruptedException {
|
public void testPrepareInvalidContentEncodingScope() throws IOException, InterruptedException {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 0, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 0, 1, 5, 1);
|
||||||
try {
|
try {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings));
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
assertEquals("ContentEncodingScope 0 not supported", exception.getMessage());
|
assertEquals("ContentEncodingScope 0 not supported", exception.getMessage());
|
||||||
|
|
@ -175,7 +233,9 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
public void testPrepareInvalidContentEncodingType() throws IOException, InterruptedException {
|
public void testPrepareInvalidContentEncodingType() throws IOException, InterruptedException {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 0, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 0, 5, 1);
|
||||||
try {
|
try {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings));
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
assertEquals("ContentEncodingType 0 not supported", exception.getMessage());
|
assertEquals("ContentEncodingType 0 not supported", exception.getMessage());
|
||||||
|
|
@ -185,7 +245,9 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
public void testPrepareInvalidContentEncAlgo() throws IOException, InterruptedException {
|
public void testPrepareInvalidContentEncAlgo() throws IOException, InterruptedException {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 4, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 4, 1);
|
||||||
try {
|
try {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings));
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
assertEquals("ContentEncAlgo 4 not supported", exception.getMessage());
|
assertEquals("ContentEncAlgo 4 not supported", exception.getMessage());
|
||||||
|
|
@ -195,7 +257,9 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
public void testPrepareInvalidAESSettingsCipherMode() throws IOException, InterruptedException {
|
public void testPrepareInvalidAESSettingsCipherMode() throws IOException, InterruptedException {
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 0);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 0);
|
||||||
try {
|
try {
|
||||||
consume(createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings));
|
consume(
|
||||||
|
createInitializationSegment(1, 0, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings));
|
||||||
fail();
|
fail();
|
||||||
} catch (ParserException exception) {
|
} catch (ParserException exception) {
|
||||||
assertEquals("AESSettingsCipherMode 0 not supported", exception.getMessage());
|
assertEquals("AESSettingsCipherMode 0 not supported", exception.getMessage());
|
||||||
|
|
@ -203,46 +267,94 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadSampleKeyframe() throws IOException, InterruptedException {
|
public void testReadSampleKeyframe() throws IOException, InterruptedException {
|
||||||
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, true, false, false);
|
MediaSegment mediaSegment =
|
||||||
|
createMediaSegment(100, 0, 0, true, false, true, false, false, 1);
|
||||||
byte[] testInputData = joinByteArrays(
|
byte[] testInputData = joinByteArrays(
|
||||||
createInitializationSegment(
|
createInitializationSegment(
|
||||||
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9, null),
|
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, null),
|
||||||
mediaSegment.clusterBytes);
|
mediaSegment.clusterBytes);
|
||||||
consume(testInputData);
|
consume(testInputData);
|
||||||
assertFormat();
|
assertVideoFormat();
|
||||||
assertSample(mediaSegment, 0, true, false, false);
|
assertSample(mediaSegment, 0, true, false, false, videoOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadTwoTrackSamples() throws IOException, InterruptedException {
|
||||||
|
MediaSegment mediaSegmentAudio =
|
||||||
|
createMediaSegment(100, 0, 0, true, false, true, false, false, 2);
|
||||||
|
MediaSegment mediaSegmentVideo =
|
||||||
|
createMediaSegment(100, 0, 0, true, false, true, false, false, 1);
|
||||||
|
byte[] testInputData = joinByteArrays(
|
||||||
|
createInitializationSegment(
|
||||||
|
1, mediaSegmentAudio.clusterBytes.length + mediaSegmentVideo.clusterBytes.length,
|
||||||
|
true, DEFAULT_TIMECODE_SCALE, new int[] {ID_VP9, ID_OPUS}, null),
|
||||||
|
mediaSegmentVideo.clusterBytes, mediaSegmentAudio.clusterBytes);
|
||||||
|
consume(testInputData);
|
||||||
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
|
assertVideoFormat();
|
||||||
|
assertAudioFormat(ID_OPUS);
|
||||||
|
assertSample(mediaSegmentVideo, 0, true, false, false, videoOutput);
|
||||||
|
assertSample(mediaSegmentAudio, 0, true, false, false, audioOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadTwoTrackSamplesWithSkippedTrack() throws IOException, InterruptedException {
|
||||||
|
MediaSegment mediaSegmentAudio =
|
||||||
|
createMediaSegment(100, 0, 0, true, false, true, false, false, 2);
|
||||||
|
MediaSegment mediaSegmentVideo =
|
||||||
|
createMediaSegment(100, 0, 0, true, false, true, false, false, 1);
|
||||||
|
MediaSegment mediaSegmentDummy =
|
||||||
|
createMediaSegment(100, 0, 0, true, false, true, false, false, 17);
|
||||||
|
byte[] testInputData = joinByteArrays(
|
||||||
|
createInitializationSegment(
|
||||||
|
1,
|
||||||
|
mediaSegmentAudio.clusterBytes.length + mediaSegmentVideo.clusterBytes.length
|
||||||
|
+ mediaSegmentDummy.clusterBytes.length,
|
||||||
|
true, DEFAULT_TIMECODE_SCALE, new int[] {ID_DUMMY, ID_VP9, ID_OPUS}, null),
|
||||||
|
mediaSegmentVideo.clusterBytes,
|
||||||
|
mediaSegmentDummy.clusterBytes,
|
||||||
|
mediaSegmentAudio.clusterBytes);
|
||||||
|
consume(testInputData);
|
||||||
|
assertEquals(2, extractorOutput.numberOfTracks);
|
||||||
|
assertVideoFormat();
|
||||||
|
assertAudioFormat(ID_OPUS);
|
||||||
|
assertSample(mediaSegmentVideo, 0, true, false, false, videoOutput);
|
||||||
|
assertSample(mediaSegmentAudio, 0, true, false, false, audioOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadBlock() throws IOException, InterruptedException {
|
public void testReadBlock() throws IOException, InterruptedException {
|
||||||
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, false, false, false);
|
MediaSegment mediaSegment =
|
||||||
|
createMediaSegment(100, 0, 0, true, false, false, false, false, 2);
|
||||||
byte[] testInputData = joinByteArrays(
|
byte[] testInputData = joinByteArrays(
|
||||||
createInitializationSegment(
|
createInitializationSegment(
|
||||||
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_OPUS, null),
|
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_OPUS}, null),
|
||||||
mediaSegment.clusterBytes);
|
mediaSegment.clusterBytes);
|
||||||
consume(testInputData);
|
consume(testInputData);
|
||||||
assertAudioFormat(ID_OPUS);
|
assertAudioFormat(ID_OPUS);
|
||||||
assertSample(mediaSegment, 0, true, false, false);
|
assertSample(mediaSegment, 0, true, false, false, audioOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadEncryptedFrame() throws IOException, InterruptedException {
|
public void testReadEncryptedFrame() throws IOException, InterruptedException {
|
||||||
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, true, true, true);
|
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, true, true, true, 1);
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 1);
|
||||||
byte[] testInputData = joinByteArrays(
|
byte[] testInputData = joinByteArrays(
|
||||||
createInitializationSegment(
|
createInitializationSegment(
|
||||||
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings),
|
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings),
|
||||||
mediaSegment.clusterBytes);
|
mediaSegment.clusterBytes);
|
||||||
consume(testInputData);
|
consume(testInputData);
|
||||||
assertFormat();
|
assertVideoFormat();
|
||||||
assertSample(mediaSegment, 0, true, false, true);
|
assertSample(mediaSegment, 0, true, false, true, videoOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadEncryptedFrameWithInvalidSignalByte()
|
public void testReadEncryptedFrameWithInvalidSignalByte()
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, true, true, false);
|
MediaSegment mediaSegment = createMediaSegment(100, 0, 0, true, false, true, true, false, 1);
|
||||||
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 1);
|
ContentEncodingSettings settings = new ContentEncodingSettings(0, 1, 1, 5, 1);
|
||||||
byte[] testInputData = joinByteArrays(
|
byte[] testInputData = joinByteArrays(
|
||||||
createInitializationSegment(
|
createInitializationSegment(
|
||||||
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9, settings),
|
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, settings),
|
||||||
mediaSegment.clusterBytes);
|
mediaSegment.clusterBytes);
|
||||||
try {
|
try {
|
||||||
consume(testInputData);
|
consume(testInputData);
|
||||||
|
|
@ -253,36 +365,41 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadSampleInvisible() throws IOException, InterruptedException {
|
public void testReadSampleInvisible() throws IOException, InterruptedException {
|
||||||
MediaSegment mediaSegment = createMediaSegment(100, 12, 13, false, true, true, false, false);
|
MediaSegment mediaSegment =
|
||||||
|
createMediaSegment(100, 12, 13, false, true, true, false, false, 1);
|
||||||
byte[] testInputData = joinByteArrays(
|
byte[] testInputData = joinByteArrays(
|
||||||
createInitializationSegment(
|
createInitializationSegment(
|
||||||
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9, null),
|
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, null),
|
||||||
mediaSegment.clusterBytes);
|
mediaSegment.clusterBytes);
|
||||||
consume(testInputData);
|
consume(testInputData);
|
||||||
assertFormat();
|
assertVideoFormat();
|
||||||
assertSample(mediaSegment, 25000, false, true, false);
|
assertSample(mediaSegment, 25000, false, true, false, videoOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadSampleCustomTimescale() throws IOException, InterruptedException {
|
public void testReadSampleCustomTimescale() throws IOException, InterruptedException {
|
||||||
MediaSegment mediaSegment = createMediaSegment(100, 12, 13, false, false, true, false, false);
|
MediaSegment mediaSegment =
|
||||||
|
createMediaSegment(100, 12, 13, false, false, true, false, false, 1);
|
||||||
byte[] testInputData = joinByteArrays(
|
byte[] testInputData = joinByteArrays(
|
||||||
createInitializationSegment(
|
createInitializationSegment(
|
||||||
1, mediaSegment.clusterBytes.length, true, 1000, ID_VP9, null),
|
1, mediaSegment.clusterBytes.length, true, 1000, new int[] {ID_VP9}, null),
|
||||||
mediaSegment.clusterBytes);
|
mediaSegment.clusterBytes);
|
||||||
consume(testInputData);
|
consume(testInputData);
|
||||||
assertFormat();
|
assertVideoFormat();
|
||||||
assertSample(mediaSegment, 25, false, false, false);
|
assertSample(mediaSegment, 25, false, false, false, videoOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadSampleNegativeSimpleBlockTimecode() throws IOException, InterruptedException {
|
public void testReadSampleNegativeSimpleBlockTimecode() throws IOException, InterruptedException {
|
||||||
MediaSegment mediaSegment = createMediaSegment(100, 13, -12, true, true, true, false, false);
|
MediaSegment mediaSegment =
|
||||||
|
createMediaSegment(100, 13, -12, true, true, true, false, false, 1);
|
||||||
byte[] testInputData = joinByteArrays(
|
byte[] testInputData = joinByteArrays(
|
||||||
createInitializationSegment(
|
createInitializationSegment(
|
||||||
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE, ID_VP9, null),
|
1, mediaSegment.clusterBytes.length, true, DEFAULT_TIMECODE_SCALE,
|
||||||
|
new int[] {ID_VP9}, null),
|
||||||
mediaSegment.clusterBytes);
|
mediaSegment.clusterBytes);
|
||||||
consume(testInputData);
|
consume(testInputData);
|
||||||
assertFormat();
|
assertVideoFormat();
|
||||||
assertSample(mediaSegment, 1000, true, true, false);
|
assertSample(mediaSegment, 1000, true, true, false, videoOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void consume(byte[] data) throws IOException, InterruptedException {
|
private void consume(byte[] data) throws IOException, InterruptedException {
|
||||||
|
|
@ -301,15 +418,15 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertFormat() {
|
private void assertVideoFormat() {
|
||||||
MediaFormat format = output.format;
|
MediaFormat format = videoOutput.format;
|
||||||
assertEquals(TEST_WIDTH, format.width);
|
assertEquals(TEST_WIDTH, format.width);
|
||||||
assertEquals(TEST_HEIGHT, format.height);
|
assertEquals(TEST_HEIGHT, format.height);
|
||||||
assertEquals(MimeTypes.VIDEO_VP9, format.mimeType);
|
assertEquals(MimeTypes.VIDEO_VP9, format.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertAudioFormat(int codecId) {
|
private void assertAudioFormat(int codecId) {
|
||||||
MediaFormat format = output.format;
|
MediaFormat format = audioOutput.format;
|
||||||
assertEquals(TEST_CHANNEL_COUNT, format.channelCount);
|
assertEquals(TEST_CHANNEL_COUNT, format.channelCount);
|
||||||
assertEquals(TEST_SAMPLE_RATE, format.sampleRate);
|
assertEquals(TEST_SAMPLE_RATE, format.sampleRate);
|
||||||
if (codecId == ID_OPUS) {
|
if (codecId == ID_OPUS) {
|
||||||
|
|
@ -327,7 +444,7 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertIndex(IndexPoint... indexPoints) {
|
private void assertIndex(IndexPoint... indexPoints) {
|
||||||
ChunkIndex index = (ChunkIndex) output.seekMap;
|
ChunkIndex index = (ChunkIndex) extractorOutput.seekMap;
|
||||||
assertEquals(indexPoints.length, index.length);
|
assertEquals(indexPoints.length, index.length);
|
||||||
for (int i = 0; i < indexPoints.length; i++) {
|
for (int i = 0; i < indexPoints.length; i++) {
|
||||||
IndexPoint indexPoint = indexPoints[i];
|
IndexPoint indexPoint = indexPoints[i];
|
||||||
|
|
@ -338,8 +455,8 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSample(MediaSegment mediaSegment, int timeUs, boolean keyframe,
|
private void assertSample(MediaSegment mediaSegment, int timeUs, boolean keyframe,
|
||||||
boolean invisible, boolean encrypted) {
|
boolean invisible, boolean encrypted, TestTrackOutput output) {
|
||||||
byte[] expectedOutput = mediaSegment.videoBytes;
|
byte[] expectedOutput = mediaSegment.data;
|
||||||
if (encrypted) {
|
if (encrypted) {
|
||||||
expectedOutput = joinByteArrays(new byte[] {(byte) TEST_INITIALIZATION_VECTOR.length},
|
expectedOutput = joinByteArrays(new byte[] {(byte) TEST_INITIALIZATION_VECTOR.length},
|
||||||
TEST_INITIALIZATION_VECTOR, expectedOutput);
|
TEST_INITIALIZATION_VECTOR, expectedOutput);
|
||||||
|
|
@ -353,24 +470,11 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createInitializationSegment(int cuePoints, int mediaSegmentSize,
|
private byte[] createInitializationSegment(int cuePoints, int mediaSegmentSize,
|
||||||
boolean docTypeIsWebm, int timecodeScale, int codecId,
|
boolean docTypeIsWebm, int timecodeScale, int[] codecIds,
|
||||||
ContentEncodingSettings contentEncodingSettings) {
|
ContentEncodingSettings contentEncodingSettings) {
|
||||||
byte[] tracksElement = null;
|
byte[] tracksElement = createTracksElement(codecIds, contentEncodingSettings);
|
||||||
switch (codecId) {
|
|
||||||
case ID_VP9:
|
|
||||||
tracksElement = createTracksElementWithVideo(
|
|
||||||
true, TEST_WIDTH, TEST_HEIGHT, contentEncodingSettings);
|
|
||||||
break;
|
|
||||||
case ID_OPUS:
|
|
||||||
tracksElement = createTracksElementWithOpusAudio(TEST_CHANNEL_COUNT);
|
|
||||||
break;
|
|
||||||
case ID_VORBIS:
|
|
||||||
tracksElement = createTracksElementWithVorbisAudio(TEST_CHANNEL_COUNT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
byte[] infoElement = createInfoElement(timecodeScale);
|
byte[] infoElement = createInfoElement(timecodeScale);
|
||||||
byte[] cuesElement = createCuesElement(CUE_POINT_ELEMENT_BYTE_SIZE * cuePoints);
|
byte[] cuesElement = createCuesElement(CUE_POINT_ELEMENT_BYTE_SIZE * cuePoints);
|
||||||
|
|
||||||
int initalizationSegmentSize = infoElement.length + tracksElement.length
|
int initalizationSegmentSize = infoElement.length + tracksElement.length
|
||||||
+ cuesElement.length + CUE_POINT_ELEMENT_BYTE_SIZE * cuePoints;
|
+ cuesElement.length + CUE_POINT_ELEMENT_BYTE_SIZE * cuePoints;
|
||||||
byte[] segmentElement = createSegmentElement(initalizationSegmentSize + mediaSegmentSize);
|
byte[] segmentElement = createSegmentElement(initalizationSegmentSize + mediaSegmentSize);
|
||||||
|
|
@ -382,20 +486,47 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MediaSegment createMediaSegment(int videoBytesLength, int clusterTimecode,
|
private byte[] createTracksElement(int[] codecIds,
|
||||||
|
ContentEncodingSettings contentEncodingSettings) {
|
||||||
|
byte[] trackBytes = new byte[0];
|
||||||
|
for (int codecId : codecIds) {
|
||||||
|
switch (codecId) {
|
||||||
|
case ID_VP9:
|
||||||
|
trackBytes = joinByteArrays(trackBytes,
|
||||||
|
createVideoTrackEntry(true, TEST_WIDTH, TEST_HEIGHT, contentEncodingSettings));
|
||||||
|
break;
|
||||||
|
case ID_OPUS:
|
||||||
|
trackBytes = joinByteArrays(trackBytes, createOpusAudioTrackEntry(TEST_CHANNEL_COUNT));
|
||||||
|
break;
|
||||||
|
case ID_VORBIS:
|
||||||
|
trackBytes = joinByteArrays(trackBytes, createVorbisAudioTrackEntry(TEST_CHANNEL_COUNT));
|
||||||
|
break;
|
||||||
|
case ID_DUMMY:
|
||||||
|
trackBytes = joinByteArrays(trackBytes, createUnsupportedTrackEntry());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] tracksSize = getIntegerBytes(trackBytes.length);
|
||||||
|
byte[] tracksHeader = createByteArray(
|
||||||
|
0x16, 0x54, 0xAE, 0x6B, // Tracks
|
||||||
|
0x01, 0x00, 0x00, 0x00, tracksSize[0], tracksSize[1], tracksSize[2], tracksSize[3]);
|
||||||
|
return joinByteArrays(tracksHeader, trackBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MediaSegment createMediaSegment(int dataLength, int clusterTimecode,
|
||||||
int blockTimecode, boolean keyframe, boolean invisible, boolean simple,
|
int blockTimecode, boolean keyframe, boolean invisible, boolean simple,
|
||||||
boolean encrypted, boolean validSignalByte) {
|
boolean encrypted, boolean validSignalByte, int trackNumber) {
|
||||||
byte[] videoBytes = createVideoBytes(videoBytesLength);
|
byte[] data = createFrameData(dataLength);
|
||||||
byte[] blockBytes;
|
byte[] blockBytes;
|
||||||
if (simple) {
|
if (simple) {
|
||||||
blockBytes = createSimpleBlockElement(videoBytes.length, blockTimecode,
|
blockBytes = createSimpleBlockElement(data.length, blockTimecode,
|
||||||
keyframe, invisible, true, encrypted, validSignalByte);
|
keyframe, invisible, true, encrypted, validSignalByte, trackNumber);
|
||||||
} else {
|
} else {
|
||||||
blockBytes = createBlockElement(videoBytes.length, blockTimecode, invisible, true);
|
blockBytes = createBlockElement(data.length, blockTimecode, invisible, true, trackNumber);
|
||||||
}
|
}
|
||||||
byte[] clusterBytes =
|
byte[] clusterBytes =
|
||||||
createClusterElement(blockBytes.length + videoBytes.length, clusterTimecode);
|
createClusterElement(blockBytes.length + data.length, clusterTimecode);
|
||||||
return new MediaSegment(joinByteArrays(clusterBytes, blockBytes, videoBytes), videoBytes);
|
return new MediaSegment(joinByteArrays(clusterBytes, blockBytes, data), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] joinByteArrays(byte[]... byteArrays) {
|
private static byte[] joinByteArrays(byte[]... byteArrays) {
|
||||||
|
|
@ -443,7 +574,7 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
0x88, 0x40, 0xC3, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00); // size=8 value=9920.0
|
0x88, 0x40, 0xC3, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00); // size=8 value=9920.0
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] createTracksElementWithVideo(
|
private static byte[] createVideoTrackEntry(
|
||||||
boolean codecIsVp9, int pixelWidth, int pixelHeight,
|
boolean codecIsVp9, int pixelWidth, int pixelHeight,
|
||||||
ContentEncodingSettings contentEncodingSettings) {
|
ContentEncodingSettings contentEncodingSettings) {
|
||||||
byte[] widthBytes = getIntegerBytes(pixelWidth);
|
byte[] widthBytes = getIntegerBytes(pixelWidth);
|
||||||
|
|
@ -455,8 +586,6 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
byte[] algorithmBytes = getIntegerBytes(contentEncodingSettings.algorithm);
|
byte[] algorithmBytes = getIntegerBytes(contentEncodingSettings.algorithm);
|
||||||
byte[] cipherModeBytes = getIntegerBytes(contentEncodingSettings.aesCipherMode);
|
byte[] cipherModeBytes = getIntegerBytes(contentEncodingSettings.aesCipherMode);
|
||||||
return createByteArray(
|
return createByteArray(
|
||||||
0x16, 0x54, 0xAE, 0x6B, // Tracks
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, // size=78
|
|
||||||
0xAE, // TrackEntry
|
0xAE, // TrackEntry
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, // size=69
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, // size=69
|
||||||
0x86, // CodecID
|
0x86, // CodecID
|
||||||
|
|
@ -495,10 +624,8 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
0x82, heightBytes[2], heightBytes[3]); // size=2
|
0x82, heightBytes[2], heightBytes[3]); // size=2
|
||||||
} else {
|
} else {
|
||||||
return createByteArray(
|
return createByteArray(
|
||||||
0x16, 0x54, 0xAE, 0x6B, // Tracks
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, // size=42
|
|
||||||
0xAE, // TrackEntry
|
0xAE, // TrackEntry
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, // size=33
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, // size=30
|
||||||
0x86, // CodecID
|
0x86, // CodecID
|
||||||
0x85, 0x56, 0x5F, 0x56, 0x50, codecIsVp9 ? 0x39 : 0x30, // size=5 value=V_VP9/0
|
0x85, 0x56, 0x5F, 0x56, 0x50, codecIsVp9 ? 0x39 : 0x30, // size=5 value=V_VP9/0
|
||||||
0xD7, // TrackNumber
|
0xD7, // TrackNumber
|
||||||
|
|
@ -514,17 +641,15 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] createTracksElementWithOpusAudio(int channelCount) {
|
private static byte[] createOpusAudioTrackEntry(int channelCount) {
|
||||||
byte[] channelCountBytes = getIntegerBytes(channelCount);
|
byte[] channelCountBytes = getIntegerBytes(channelCount);
|
||||||
return createByteArray(
|
return createByteArray(
|
||||||
0x16, 0x54, 0xAE, 0x6B, // Tracks
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, // size=63
|
|
||||||
0xAE, // TrackEntry
|
0xAE, // TrackEntry
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, // size=54
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, // size=54
|
||||||
0x86, // CodecID
|
0x86, // CodecID
|
||||||
0x86, 0x41, 0x5F, 0x4F, 0x50, 0x55, 0x53, // size=6 value=A_OPUS
|
0x86, 0x41, 0x5F, 0x4F, 0x50, 0x55, 0x53, // size=6 value=A_OPUS
|
||||||
0xD7, // TrackNumber
|
0xD7, // TrackNumber
|
||||||
0x81, 0x01, // size=1 value=1
|
0x81, 0x02, // size=1 value=2
|
||||||
0x83, // TrackType
|
0x83, // TrackType
|
||||||
0x81, 0x02, // size=1 value=2
|
0x81, 0x02, // size=1 value=2
|
||||||
0x56, 0xAA, // CodecDelay
|
0x56, 0xAA, // CodecDelay
|
||||||
|
|
@ -541,17 +666,15 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
0x82, 0x00, 0x00); // size=2
|
0x82, 0x00, 0x00); // size=2
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createTracksElementWithVorbisAudio(int channelCount) {
|
private byte[] createVorbisAudioTrackEntry(int channelCount) {
|
||||||
byte[] channelCountBytes = getIntegerBytes(channelCount);
|
byte[] channelCountBytes = getIntegerBytes(channelCount);
|
||||||
byte[] tracksElement = createByteArray(
|
byte[] tracksElement = createByteArray(
|
||||||
0x16, 0x54, 0xAE, 0x6B, // Tracks
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA2, // size=4258
|
|
||||||
0xAE, // TrackEntry
|
0xAE, // TrackEntry
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, // size=4249 (42+4207)
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, // size=4249 (42+4207)
|
||||||
0x86, // CodecID
|
0x86, // CodecID
|
||||||
0x88, 0x41, 0x5f, 0x56, 0x4f, 0x52, 0x42, 0x49, 0x53, // size=8 value=A_VORBIS
|
0x88, 0x41, 0x5f, 0x56, 0x4f, 0x52, 0x42, 0x49, 0x53, // size=8 value=A_VORBIS
|
||||||
0xD7, // TrackNumber
|
0xD7, // TrackNumber
|
||||||
0x81, 0x01, // size=1 value=1
|
0x81, 0x02, // size=1 value=2
|
||||||
0x83, // TrackType
|
0x83, // TrackType
|
||||||
0x81, 0x02, // size=1 value=2
|
0x81, 0x02, // size=1 value=2
|
||||||
0xE1, // Audio
|
0xE1, // Audio
|
||||||
|
|
@ -572,6 +695,20 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
return joinByteArrays(tracksElement, codecPrivate);
|
return joinByteArrays(tracksElement, codecPrivate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte[] createUnsupportedTrackEntry() {
|
||||||
|
return createByteArray(
|
||||||
|
0xAE, // TrackEntry
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, // size=32
|
||||||
|
0x86, // CodecID
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, // size =17
|
||||||
|
0x44, 0x5f, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54,
|
||||||
|
0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, // value=D_WEBVTT/metadata
|
||||||
|
0xD7, // TrackNumber
|
||||||
|
0x81, 0x03, // size=1 value=3
|
||||||
|
0x83, // TrackType
|
||||||
|
0x81, 0x11); // size=1 value=11
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] createCuesElement(int size) {
|
private static byte[] createCuesElement(int size) {
|
||||||
byte[] sizeBytes = getIntegerBytes(size);
|
byte[] sizeBytes = getIntegerBytes(size);
|
||||||
return createByteArray(
|
return createByteArray(
|
||||||
|
|
@ -605,15 +742,16 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
private static byte[] createSimpleBlockElement(
|
private static byte[] createSimpleBlockElement(
|
||||||
int size, int timecode, boolean keyframe, boolean invisible, boolean noLacing,
|
int size, int timecode, boolean keyframe, boolean invisible, boolean noLacing,
|
||||||
boolean encrypted, boolean validSignalByte) {
|
boolean encrypted, boolean validSignalByte, int trackNumber) {
|
||||||
byte[] sizeBytes = getIntegerBytes(size + 4 + (encrypted ? 9 : 0));
|
byte[] sizeBytes = getIntegerBytes(size + 5 + (encrypted ? 9 : 0));
|
||||||
byte[] timeBytes = getIntegerBytes(timecode);
|
byte[] timeBytes = getIntegerBytes(timecode);
|
||||||
|
byte[] trackNumberBytes = getIntegerBytes(trackNumber);
|
||||||
byte flags = (byte)
|
byte flags = (byte)
|
||||||
((keyframe ? 0x80 : 0x00) | (invisible ? 0x08 : 0x00) | (noLacing ? 0x00 : 0x06));
|
((keyframe ? 0x80 : 0x00) | (invisible ? 0x08 : 0x00) | (noLacing ? 0x00 : 0x06));
|
||||||
byte[] simpleBlock = createByteArray(
|
byte[] simpleBlock = createByteArray(
|
||||||
0xA3, // SimpleBlock
|
0xA3, // SimpleBlock
|
||||||
0x01, 0x00, 0x00, 0x00, sizeBytes[0], sizeBytes[1], sizeBytes[2], sizeBytes[3],
|
0x01, 0x00, 0x00, 0x00, sizeBytes[0], sizeBytes[1], sizeBytes[2], sizeBytes[3],
|
||||||
0x81, // Track number value=1
|
0x40, trackNumberBytes[3], // Track number size=2
|
||||||
timeBytes[2], timeBytes[3], flags); // Timecode and flags
|
timeBytes[2], timeBytes[3], flags); // Timecode and flags
|
||||||
if (encrypted) {
|
if (encrypted) {
|
||||||
simpleBlock = joinByteArrays(
|
simpleBlock = joinByteArrays(
|
||||||
|
|
@ -624,10 +762,11 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] createBlockElement(
|
private static byte[] createBlockElement(
|
||||||
int size, int timecode, boolean invisible, boolean noLacing) {
|
int size, int timecode, boolean invisible, boolean noLacing, int trackNumber) {
|
||||||
int blockSize = size + 4;
|
int blockSize = size + 5;
|
||||||
byte[] blockSizeBytes = getIntegerBytes(blockSize);
|
byte[] blockSizeBytes = getIntegerBytes(blockSize);
|
||||||
byte[] timeBytes = getIntegerBytes(timecode);
|
byte[] timeBytes = getIntegerBytes(timecode);
|
||||||
|
byte[] trackNumberBytes = getIntegerBytes(trackNumber);
|
||||||
int blockElementSize = 1 + 8 + blockSize; // id + size + length of data
|
int blockElementSize = 1 + 8 + blockSize; // id + size + length of data
|
||||||
byte[] sizeBytes = getIntegerBytes(blockElementSize);
|
byte[] sizeBytes = getIntegerBytes(blockElementSize);
|
||||||
byte flags = (byte) ((invisible ? 0x08 : 0x00) | (noLacing ? 0x00 : 0x06));
|
byte flags = (byte) ((invisible ? 0x08 : 0x00) | (noLacing ? 0x00 : 0x06));
|
||||||
|
|
@ -637,16 +776,16 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
0xA1, // Block
|
0xA1, // Block
|
||||||
0x01, 0x00, 0x00, 0x00,
|
0x01, 0x00, 0x00, 0x00,
|
||||||
blockSizeBytes[0], blockSizeBytes[1], blockSizeBytes[2], blockSizeBytes[3],
|
blockSizeBytes[0], blockSizeBytes[1], blockSizeBytes[2], blockSizeBytes[3],
|
||||||
0x81, // Track number value=1
|
0x40, trackNumberBytes[3], // Track number size=2
|
||||||
timeBytes[2], timeBytes[3], flags); // Timecode and flags
|
timeBytes[2], timeBytes[3], flags); // Timecode and flags
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] createVideoBytes(int size) {
|
private static byte[] createFrameData(int size) {
|
||||||
byte[] videoBytes = new byte[size];
|
byte[] data = new byte[size];
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
videoBytes[i] = (byte) i;
|
data[i] = (byte) i;
|
||||||
}
|
}
|
||||||
return videoBytes;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getIntegerBytes(int value) {
|
private static byte[] getIntegerBytes(int value) {
|
||||||
|
|
@ -669,11 +808,11 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
private static final class MediaSegment {
|
private static final class MediaSegment {
|
||||||
|
|
||||||
private final byte[] clusterBytes;
|
private final byte[] clusterBytes;
|
||||||
private final byte[] videoBytes;
|
private final byte[] data;
|
||||||
|
|
||||||
private MediaSegment(byte[] clusterBytes, byte[] videoBytes) {
|
private MediaSegment(byte[] clusterBytes, byte[] data) {
|
||||||
this.clusterBytes = clusterBytes;
|
this.clusterBytes = clusterBytes;
|
||||||
this.videoBytes = videoBytes;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -713,21 +852,19 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implements {@link ExtractorOutput} and {@link TrackOutput} for test purposes. */
|
/** Implements {@link ExtractorOutput} for test purposes. */
|
||||||
public static class TestOutput implements ExtractorOutput, TrackOutput {
|
public class TestExtractorOutput implements ExtractorOutput {
|
||||||
|
|
||||||
public boolean tracksEnded;
|
public boolean tracksEnded;
|
||||||
public SeekMap seekMap;
|
public SeekMap seekMap;
|
||||||
public DrmInitData drmInitData;
|
public DrmInitData drmInitData;
|
||||||
|
public int numberOfTracks;
|
||||||
public MediaFormat format;
|
|
||||||
private long sampleTimeUs;
|
|
||||||
private int sampleFlags;
|
|
||||||
private byte[] sampleData;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackOutput track(int trackId) {
|
public TrackOutput track(int trackId) {
|
||||||
return this;
|
numberOfTracks++;
|
||||||
|
// In the test samples, track number 1 is always video and track number 2 is always audio.
|
||||||
|
return (trackId == 1) ? videoOutput : audioOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -745,6 +882,16 @@ public class WebmExtractorTest extends InstrumentationTestCase {
|
||||||
this.drmInitData = drmInitData;
|
this.drmInitData = drmInitData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Implements {@link TrackOutput} for test purposes. */
|
||||||
|
public static class TestTrackOutput implements TrackOutput {
|
||||||
|
|
||||||
|
public MediaFormat format;
|
||||||
|
private long sampleTimeUs;
|
||||||
|
private int sampleFlags;
|
||||||
|
private byte[] sampleData;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void format(MediaFormat format) {
|
public void format(MediaFormat format) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue