mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Move OGG extractor to use FakeExtractorInput + Simplify.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=117220360
This commit is contained in:
parent
bccffb017d
commit
7cddd1b1d9
7 changed files with 229 additions and 673 deletions
|
|
@ -15,78 +15,73 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.extractor.ogg;
|
package com.google.android.exoplayer.extractor.ogg;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.testutil.FakeExtractorInput;
|
||||||
|
import com.google.android.exoplayer.testutil.FakeExtractorInput.SimulatedIOException;
|
||||||
|
import com.google.android.exoplayer.testutil.TestUtil;
|
||||||
import com.google.android.exoplayer.util.ParsableByteArray;
|
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.test.MoreAsserts;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for {@link OggReader}
|
* Unit test for {@link OggReader}
|
||||||
*/
|
*/
|
||||||
public final class OggReaderTest extends TestCase {
|
public final class OggReaderTest extends TestCase {
|
||||||
|
|
||||||
private static final String TAG = "OggReaderTest";
|
private Random random;
|
||||||
|
|
||||||
private OggReader oggReader;
|
private OggReader oggReader;
|
||||||
private RecordableOggExtractorInput extractorInput;
|
private ParsableByteArray scratch;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
extractorInput = new RecordableOggExtractorInput(1024 * 64);
|
random = new Random(0);
|
||||||
// we want the mocked ExtractorInput to throw errors often
|
|
||||||
extractorInput.doThrowExceptionsAtPeek(true);
|
|
||||||
extractorInput.doThrowExceptionsAtRead(true);
|
|
||||||
// create reader
|
|
||||||
oggReader = new OggReader();
|
oggReader = new OggReader();
|
||||||
oggReader.reset();
|
scratch = new ParsableByteArray(new byte[255 * 255], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadPacketUntilEOFIncludingAnEmptyPage() throws Exception {
|
public void testReadPacketsWithEmptyPage() throws Exception {
|
||||||
// record first page with a single packet
|
byte[] firstPacket = TestUtil.buildTestData(8, random);
|
||||||
extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x01);
|
byte[] secondPacket = TestUtil.buildTestData(272, random);
|
||||||
extractorInput.recordOggLaces(new byte[]{0x08});
|
byte[] thirdPacket = TestUtil.buildTestData(256, random);
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8));
|
byte[] fourthPacket = TestUtil.buildTestData(271, random);
|
||||||
// record intermediate page with two packets
|
|
||||||
extractorInput.recordOggHeader((byte) 0x00, 16, (byte) 0x02);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, 0x11});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255 + 17));
|
|
||||||
// empty page
|
|
||||||
extractorInput.recordOggHeader((byte) 0x00, 16, (byte) 0x00);
|
|
||||||
// record last page with two packets (256 and 271 bytes)
|
|
||||||
extractorInput.recordOggHeader((byte) 0x04, 128, (byte) 0x04);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, 0x01, (byte) 0xff, 0x10});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput
|
|
||||||
.getBytesGrowingValues(255 + 1 + 255 + 16));
|
|
||||||
|
|
||||||
|
FakeExtractorInput input = createInput(
|
||||||
|
TestUtil.joinByteArrays(
|
||||||
|
// First page with a single packet.
|
||||||
|
TestData.buildOggHeader(0x02, 0, 1000, 0x01),
|
||||||
|
TestUtil.createByteArray(0x08), // Laces
|
||||||
|
firstPacket,
|
||||||
|
// Second page with a single packet.
|
||||||
|
TestData.buildOggHeader(0x00, 16, 1001, 0x02),
|
||||||
|
TestUtil.createByteArray(0xFF, 0x11), // Laces
|
||||||
|
secondPacket,
|
||||||
|
// Third page with zero packets.
|
||||||
|
TestData.buildOggHeader(0x00, 16, 1002, 0x00),
|
||||||
|
// Fourth page with two packets.
|
||||||
|
TestData.buildOggHeader(0x04, 128, 1003, 0x04),
|
||||||
|
TestUtil.createByteArray(0xFF, 0x01, 0xFF, 0x10), // Laces
|
||||||
|
thirdPacket,
|
||||||
|
fourthPacket));
|
||||||
|
|
||||||
// read first packet
|
assertReadPacket(input, firstPacket);
|
||||||
final ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0);
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
// verify
|
|
||||||
assertEquals(8, packetArray.limit());
|
|
||||||
assertTrue((oggReader.getPageHeader().type & 0x02) == 0x02);
|
assertTrue((oggReader.getPageHeader().type & 0x02) == 0x02);
|
||||||
assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04);
|
assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04);
|
||||||
assertEquals(0x02, oggReader.getPageHeader().type);
|
assertEquals(0x02, oggReader.getPageHeader().type);
|
||||||
assertEquals(27 + 1, oggReader.getPageHeader().headerSize);
|
assertEquals(27 + 1, oggReader.getPageHeader().headerSize);
|
||||||
assertEquals(8, oggReader.getPageHeader().bodySize);
|
assertEquals(8, oggReader.getPageHeader().bodySize);
|
||||||
assertEquals(RecordableOggExtractorInput.STREAM_REVISION, oggReader.getPageHeader().revision);
|
assertEquals(0x00, oggReader.getPageHeader().revision);
|
||||||
assertEquals(1, oggReader.getPageHeader().pageSegmentCount);
|
assertEquals(1, oggReader.getPageHeader().pageSegmentCount);
|
||||||
assertEquals(1000, oggReader.getPageHeader().pageSequenceNumber);
|
assertEquals(1000, oggReader.getPageHeader().pageSequenceNumber);
|
||||||
assertEquals(4096, oggReader.getPageHeader().streamSerialNumber);
|
assertEquals(4096, oggReader.getPageHeader().streamSerialNumber);
|
||||||
assertEquals(0, oggReader.getPageHeader().granulePosition);
|
assertEquals(0, oggReader.getPageHeader().granulePosition);
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
assertEquals(i, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
|
|
||||||
packetArray.reset();
|
assertReadPacket(input, secondPacket);
|
||||||
// read second packet
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
// verify
|
|
||||||
assertEquals(255 + 17, packetArray.limit());
|
|
||||||
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
||||||
assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04);
|
assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04);
|
||||||
assertEquals(0, oggReader.getPageHeader().type);
|
assertEquals(0, oggReader.getPageHeader().type);
|
||||||
|
|
@ -96,251 +91,140 @@ public final class OggReaderTest extends TestCase {
|
||||||
assertEquals(1001, oggReader.getPageHeader().pageSequenceNumber);
|
assertEquals(1001, oggReader.getPageHeader().pageSequenceNumber);
|
||||||
assertEquals(16, oggReader.getPageHeader().granulePosition);
|
assertEquals(16, oggReader.getPageHeader().granulePosition);
|
||||||
|
|
||||||
packetArray.reset();
|
assertReadPacket(input, thirdPacket);
|
||||||
// read next packet and skip empty page
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
// verify
|
|
||||||
assertEquals(255 + 1, packetArray.limit());
|
|
||||||
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
||||||
assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04);
|
assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04);
|
||||||
assertEquals(4, oggReader.getPageHeader().type);
|
assertEquals(4, oggReader.getPageHeader().type);
|
||||||
assertEquals(27 + 4, oggReader.getPageHeader().headerSize);
|
assertEquals(27 + 4, oggReader.getPageHeader().headerSize);
|
||||||
assertEquals(255 + 1 + 255 + 16, oggReader.getPageHeader().bodySize);
|
assertEquals(255 + 1 + 255 + 16, oggReader.getPageHeader().bodySize);
|
||||||
assertEquals(4, oggReader.getPageHeader().pageSegmentCount);
|
assertEquals(4, oggReader.getPageHeader().pageSegmentCount);
|
||||||
// page 1002 is empty, so current is 1003
|
// Page 1002 is empty, so current page is 1003.
|
||||||
assertEquals(1003, oggReader.getPageHeader().pageSequenceNumber);
|
assertEquals(1003, oggReader.getPageHeader().pageSequenceNumber);
|
||||||
assertEquals(128, oggReader.getPageHeader().granulePosition);
|
assertEquals(128, oggReader.getPageHeader().granulePosition);
|
||||||
|
|
||||||
packetArray.reset();
|
assertReadPacket(input, fourthPacket);
|
||||||
// read last packet
|
|
||||||
readPacketUntilSuccess(packetArray);
|
assertReadEof(input);
|
||||||
assertEquals(255 + 16, packetArray.limit());
|
|
||||||
// EOF!
|
|
||||||
readEOFUntilSuccess(packetArray, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadPacketWithZeroSizeTerminator() throws Exception {
|
public void testReadPacketWithZeroSizeTerminator() throws Exception {
|
||||||
// record first page with a single packet
|
byte[] firstPacket = TestUtil.buildTestData(255, random);
|
||||||
extractorInput.recordOggHeader((byte) 0x06, 0, (byte) 0x04);
|
byte[] secondPacket = TestUtil.buildTestData(8, random);
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0xff, 0x00, 0x00, 0x08});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255 + 8));
|
|
||||||
|
|
||||||
ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0);
|
FakeExtractorInput input = createInput(
|
||||||
readPacketUntilSuccess(packetArray);
|
TestUtil.joinByteArrays(
|
||||||
assertEquals(255, packetArray.limit());
|
TestData.buildOggHeader(0x06, 0, 1000, 0x04),
|
||||||
|
TestUtil.createByteArray(0xFF, 0x00, 0x00, 0x08), // Laces.
|
||||||
|
firstPacket,
|
||||||
|
secondPacket));
|
||||||
|
|
||||||
packetArray.reset();
|
assertReadPacket(input, firstPacket);
|
||||||
readPacketUntilSuccess(packetArray);
|
assertReadPacket(input, secondPacket);
|
||||||
assertEquals(8, packetArray.limit());
|
assertReadEof(input);
|
||||||
|
|
||||||
readEOFUntilSuccess(packetArray, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadContinuedPacket() throws Exception {
|
public void testReadContinuedPacketOverTwoPages() throws Exception {
|
||||||
// record first page with a packet continuing on the second page
|
byte[] firstPacket = TestUtil.buildTestData(518);
|
||||||
extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, (byte) 0xFF});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(510));
|
|
||||||
// record the continuing page
|
|
||||||
extractorInput.recordOggHeader((byte) 0x05, 10, (byte) 0x01);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{0x08});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8, (byte) 0x22));
|
|
||||||
|
|
||||||
// there is only one single packet across two pages
|
FakeExtractorInput input = createInput(
|
||||||
ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0);
|
TestUtil.joinByteArrays(
|
||||||
readPacketUntilSuccess(packetArray);
|
// First page.
|
||||||
|
TestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
||||||
|
TestUtil.createByteArray(0xFF, 0xFF), // Laces.
|
||||||
|
Arrays.copyOf(firstPacket, 510),
|
||||||
|
// Second page (continued packet).
|
||||||
|
TestData.buildOggHeader(0x05, 10, 1001, 0x01),
|
||||||
|
TestUtil.createByteArray(0x08), // Laces.
|
||||||
|
Arrays.copyOfRange(firstPacket, 510, 510 + 8)));
|
||||||
|
|
||||||
assertEquals(255 + 255 + 8, packetArray.limit());
|
assertReadPacket(input, firstPacket);
|
||||||
assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04);
|
assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04);
|
||||||
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
||||||
// we must be on the second page already
|
|
||||||
assertEquals(1001, oggReader.getPageHeader().pageSequenceNumber);
|
assertEquals(1001, oggReader.getPageHeader().pageSequenceNumber);
|
||||||
|
|
||||||
// verify packet data
|
assertReadEof(input);
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
assertEquals(i, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(255, packetArray.getPosition());
|
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
assertEquals(i, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(510, packetArray.getPosition());
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
assertEquals(i + 0x22, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(0, packetArray.bytesLeft());
|
|
||||||
// EOF!
|
|
||||||
readEOFUntilSuccess(packetArray, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no one does this with vorbis buts it's supported
|
public void testReadContinuedPacketOverFourPages() throws Exception {
|
||||||
public void testReadContinuedPacketOverMoreThan2Pages() throws Exception {
|
byte[] firstPacket = TestUtil.buildTestData(1028);
|
||||||
// record first page with a packet continuing on the second page
|
|
||||||
extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0xFF, (byte) 0xFF});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(510));
|
|
||||||
// record the first continuing page
|
|
||||||
extractorInput.recordOggHeader((byte) 0x01, 10, (byte) 0x01);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0xFF});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255));
|
|
||||||
// record the second continuing page
|
|
||||||
extractorInput.recordOggHeader((byte) 0x01, 10, (byte) 0x01);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0xFF});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(255));
|
|
||||||
// record the third continuing page
|
|
||||||
extractorInput.recordOggHeader((byte) 0x05, 10, (byte) 0x01);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0x08});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8, (byte) 0x22));
|
|
||||||
|
|
||||||
// there is only one single packet across two pages
|
FakeExtractorInput input = createInput(
|
||||||
ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0);
|
TestUtil.joinByteArrays(
|
||||||
readPacketUntilSuccess(packetArray);
|
// First page.
|
||||||
|
TestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
||||||
|
TestUtil.createByteArray(0xFF, 0xFF), // Laces.
|
||||||
|
Arrays.copyOf(firstPacket, 510),
|
||||||
|
// Second page (continued packet).
|
||||||
|
TestData.buildOggHeader(0x01, 10, 1001, 0x01),
|
||||||
|
TestUtil.createByteArray(0xFF), // Laces.
|
||||||
|
Arrays.copyOfRange(firstPacket, 510, 510 + 255),
|
||||||
|
// Third page (continued packet).
|
||||||
|
TestData.buildOggHeader(0x01, 10, 1002, 0x01),
|
||||||
|
TestUtil.createByteArray(0xFF), // Laces.
|
||||||
|
Arrays.copyOfRange(firstPacket, 510 + 255, 510 + 255 + 255),
|
||||||
|
// Fourth page (continued packet).
|
||||||
|
TestData.buildOggHeader(0x05, 10, 1003, 0x01),
|
||||||
|
TestUtil.createByteArray(0x08), // Laces.
|
||||||
|
Arrays.copyOfRange(firstPacket, 510 + 255 + 255, 510 + 255 + 255 + 8)));
|
||||||
|
|
||||||
assertEquals(255 + 255 + 255 + 255 + 8, packetArray.limit());
|
assertReadPacket(input, firstPacket);
|
||||||
assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04);
|
assertTrue((oggReader.getPageHeader().type & 0x04) == 0x04);
|
||||||
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
assertFalse((oggReader.getPageHeader().type & 0x02) == 0x02);
|
||||||
// we must be on the fourth page already
|
|
||||||
assertEquals(1003, oggReader.getPageHeader().pageSequenceNumber);
|
assertEquals(1003, oggReader.getPageHeader().pageSequenceNumber);
|
||||||
|
|
||||||
// verify packet data
|
assertReadEof(input);
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
assertEquals(i, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(255, packetArray.getPosition());
|
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
assertEquals(i, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(510, packetArray.getPosition());
|
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
assertEquals(i, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(765, packetArray.getPosition());
|
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
assertEquals(i, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(1020, packetArray.getPosition());
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
assertEquals(i + 0x22, packetArray.readUnsignedByte());
|
|
||||||
}
|
|
||||||
assertEquals(0, packetArray.bytesLeft());
|
|
||||||
// EOF!
|
|
||||||
readEOFUntilSuccess(packetArray, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testReadExceptionThrownWhilePeekingHeader() throws Exception {
|
|
||||||
// record first page with two packets packet
|
|
||||||
extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0x01, (byte) 0x08});
|
|
||||||
extractorInput.recordOggPacket(new byte[]{0x10});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8));
|
|
||||||
|
|
||||||
// record next page
|
|
||||||
extractorInput.recordOggHeader((byte) 0x05, 10, (byte) 0x01);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{0x08});
|
|
||||||
extractorInput.recordOggPacket(RecordableExtractorInput.getBytesGrowingValues(8, (byte) 0x22));
|
|
||||||
|
|
||||||
ParsableByteArray packetArray = new ParsableByteArray(new byte[255 * 255], 0);
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
// verify packet data
|
|
||||||
assertEquals(1, packetArray.limit());
|
|
||||||
assertEquals(0x10, packetArray.data[0]);
|
|
||||||
// verify header
|
|
||||||
assertTrue((oggReader.getPageHeader().type & 0x02) == 0x02);
|
|
||||||
assertFalse((oggReader.getPageHeader().type & 0x04) == 0x04);
|
|
||||||
assertEquals(27 + 2, oggReader.getPageHeader().headerSize);
|
|
||||||
assertEquals(9, oggReader.getPageHeader().bodySize);
|
|
||||||
assertEquals(2, oggReader.getPageHeader().pageSegmentCount);
|
|
||||||
assertEquals(1000, oggReader.getPageHeader().pageSequenceNumber);
|
|
||||||
assertEquals(0, oggReader.getPageHeader().granulePosition);
|
|
||||||
|
|
||||||
packetArray.reset();
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testReadNoZeroSizedPacketsAreReturned() throws Exception {
|
|
||||||
extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x04);
|
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x08});
|
|
||||||
extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10});
|
|
||||||
extractorInput.recordOggPacket(new byte[]{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20});
|
|
||||||
|
|
||||||
ParsableByteArray packetArray = new ParsableByteArray(new byte[1024], 0);
|
|
||||||
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
assertEquals(8, packetArray.limit());
|
|
||||||
assertEquals(0x10, packetArray.data[0]);
|
|
||||||
assertEquals(0x10, packetArray.data[7]);
|
|
||||||
|
|
||||||
packetArray.reset();
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
assertEquals(8, packetArray.limit());
|
|
||||||
assertEquals(0x20, packetArray.data[0]);
|
|
||||||
assertEquals(0x20, packetArray.data[7]);
|
|
||||||
|
|
||||||
readEOFUntilSuccess(packetArray, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadZeroSizedPacketsAtEndOfStream() throws Exception {
|
public void testReadZeroSizedPacketsAtEndOfStream() throws Exception {
|
||||||
extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x01);
|
byte[] firstPacket = TestUtil.buildTestData(8, random);
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0x08});
|
byte[] secondPacket = TestUtil.buildTestData(8, random);
|
||||||
extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10});
|
byte[] thirdPacket = TestUtil.buildTestData(8, random);
|
||||||
|
|
||||||
extractorInput.recordOggHeader((byte) 0x04, 0, (byte) 0x03);
|
FakeExtractorInput input = createInput(
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0x08, (byte) 0x00, (byte) 0x00});
|
TestUtil.joinByteArrays(
|
||||||
extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10});
|
TestData.buildOggHeader(0x02, 0, 1000, 0x01),
|
||||||
|
TestUtil.createByteArray(0x08), // Laces.
|
||||||
|
firstPacket,
|
||||||
|
TestData.buildOggHeader(0x04, 0, 1001, 0x03),
|
||||||
|
TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
|
||||||
|
secondPacket,
|
||||||
|
TestData.buildOggHeader(0x04, 0, 1002, 0x03),
|
||||||
|
TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
|
||||||
|
thirdPacket));
|
||||||
|
|
||||||
extractorInput.recordOggHeader((byte) 0x04, 0, (byte) 0x03);
|
assertReadPacket(input, firstPacket);
|
||||||
extractorInput.recordOggLaces(new byte[]{(byte) 0x08, 0x00, 0x00});
|
assertReadPacket(input, secondPacket);
|
||||||
extractorInput.recordOggPacket(new byte[]{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10});
|
assertReadPacket(input, thirdPacket);
|
||||||
|
assertReadEof(input);
|
||||||
ParsableByteArray packetArray = new ParsableByteArray(new byte[1024], 0);
|
|
||||||
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
assertEquals(8, packetArray.limit());
|
|
||||||
|
|
||||||
packetArray.reset();
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
assertEquals(8, packetArray.limit());
|
|
||||||
|
|
||||||
packetArray.reset();
|
|
||||||
readPacketUntilSuccess(packetArray);
|
|
||||||
assertEquals(8, packetArray.limit());
|
|
||||||
|
|
||||||
packetArray.reset();
|
|
||||||
readEOFUntilSuccess(packetArray, 10);
|
|
||||||
assertEquals(0, packetArray.limit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readPacketUntilSuccess(ParsableByteArray packetArray) {
|
private static FakeExtractorInput createInput(byte[] data) {
|
||||||
int exceptionCount = 0;
|
return new FakeExtractorInput.Builder().setData(data).setSimulateIOErrors(true)
|
||||||
while (exceptionCount < 10) {
|
.setSimulateUnknownLength(true).setSimulatePartialReads(true).build();
|
||||||
try {
|
|
||||||
assertTrue(oggReader.readPacket(extractorInput, packetArray));
|
|
||||||
break;
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
exceptionCount++;
|
|
||||||
extractorInput.resetPeekPosition();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exceptionCount == 10) {
|
|
||||||
fail("maxException threshold reached");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readEOFUntilSuccess(ParsableByteArray packetArray, int maxExceptions) {
|
private void assertReadPacket(FakeExtractorInput extractorInput, byte[] expected)
|
||||||
int exceptionCount = 0;
|
throws IOException, InterruptedException {
|
||||||
while (exceptionCount < maxExceptions) {
|
scratch.reset();
|
||||||
|
assertTrue(readPacket(extractorInput, scratch));
|
||||||
|
MoreAsserts.assertEquals(expected, Arrays.copyOf(scratch.data, scratch.limit()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertReadEof(FakeExtractorInput extractorInput)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
scratch.reset();
|
||||||
|
assertFalse(readPacket(extractorInput, scratch));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean readPacket(FakeExtractorInput input, ParsableByteArray scratch)
|
||||||
|
throws InterruptedException, IOException {
|
||||||
|
while (true) {
|
||||||
try {
|
try {
|
||||||
assertFalse(oggReader.readPacket(extractorInput, packetArray));
|
return oggReader.readPacket(input, scratch);
|
||||||
break;
|
} catch (SimulatedIOException e) {
|
||||||
} catch (IOException | InterruptedException e) {
|
// Ignore.
|
||||||
exceptionCount++;
|
|
||||||
Log.e(TAG, e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exceptionCount == maxExceptions) {
|
|
||||||
fail("maxException threshold reached");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,38 +15,41 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.extractor.ogg;
|
package com.google.android.exoplayer.extractor.ogg;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.extractor.ogg.OggVorbisExtractor.VorbisSetup;
|
||||||
|
import com.google.android.exoplayer.testutil.FakeExtractorInput;
|
||||||
|
import com.google.android.exoplayer.testutil.FakeExtractorInput.SimulatedIOException;
|
||||||
|
import com.google.android.exoplayer.testutil.TestUtil;
|
||||||
import com.google.android.exoplayer.util.ParsableByteArray;
|
import com.google.android.exoplayer.util.ParsableByteArray;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for {@link OggVorbisExtractor}.
|
* Unit test for {@link OggVorbisExtractor}.
|
||||||
*/
|
*/
|
||||||
public final class OggVorbisExtractorTest extends TestCase {
|
public final class OggVorbisExtractorTest extends TestCase {
|
||||||
|
|
||||||
private static final String TAG = "OggVorbisExtractorTest";
|
|
||||||
|
|
||||||
private OggVorbisExtractor extractor;
|
private OggVorbisExtractor extractor;
|
||||||
private RecordableOggExtractorInput extractorInput;
|
private ParsableByteArray scratch;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
extractorInput = new RecordableOggExtractorInput(1024 * 64);
|
|
||||||
extractor = new OggVorbisExtractor();
|
extractor = new OggVorbisExtractor();
|
||||||
|
scratch = new ParsableByteArray(new byte[255 * 255], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSniff() throws Exception {
|
public void testSniff() throws Exception {
|
||||||
extractorInput.recordOggHeader((byte) 0x02, 0, (byte) 0x02);
|
byte[] data = TestUtil.joinByteArrays(
|
||||||
extractorInput.recordOggLaces(new byte[]{120, 120});
|
TestData.buildOggHeader(0x02, 0, 1000, 0x02),
|
||||||
assertTrue(extractor.sniff(extractorInput));
|
TestUtil.createByteArray(120, 120)); // Laces
|
||||||
|
assertTrue(sniff(createInput(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSniffFails() throws Exception {
|
public void testSniffFails() throws Exception {
|
||||||
extractorInput.recordOggHeader((byte) 0x00, 0, (byte) 0);
|
byte[] data = TestData.buildOggHeader(0x00, 0, 1000, 0x00);
|
||||||
assertFalse(extractor.sniff(extractorInput));
|
assertFalse(sniff(createInput(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAppendNumberOfSamples() throws Exception {
|
public void testAppendNumberOfSamples() throws Exception {
|
||||||
|
|
@ -60,57 +63,62 @@ public final class OggVorbisExtractorTest extends TestCase {
|
||||||
assertEquals(0x01, buffer.data[3]);
|
assertEquals(0x01, buffer.data[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReadSetupHeadersWithIOExceptions() {
|
public void testReadSetupHeadersWithIOExceptions() throws IOException, InterruptedException {
|
||||||
extractorInput.doThrowExceptionsAtRead(true);
|
|
||||||
extractorInput.doThrowExceptionsAtPeek(true);
|
|
||||||
|
|
||||||
byte[] data = TestData.getVorbisHeaderPages();
|
byte[] data = TestData.getVorbisHeaderPages();
|
||||||
extractorInput.record(data);
|
OggVorbisExtractor.VorbisSetup vorbisSetup = readSetupHeaders(createInput(data));
|
||||||
|
|
||||||
int exceptionCount = 0;
|
assertNotNull(vorbisSetup.idHeader);
|
||||||
int maxExceptions = 20;
|
assertNotNull(vorbisSetup.commentHeader);
|
||||||
OggVorbisExtractor.VorbisSetup vorbisSetup;
|
assertNotNull(vorbisSetup.setupHeaderData);
|
||||||
while (exceptionCount < maxExceptions) {
|
assertNotNull(vorbisSetup.modes);
|
||||||
|
|
||||||
|
assertEquals(45, vorbisSetup.commentHeader.length);
|
||||||
|
assertEquals(30, vorbisSetup.idHeader.data.length);
|
||||||
|
assertEquals(3597, vorbisSetup.setupHeaderData.length);
|
||||||
|
|
||||||
|
assertEquals(-1, vorbisSetup.idHeader.bitrateMax);
|
||||||
|
assertEquals(-1, vorbisSetup.idHeader.bitrateMin);
|
||||||
|
assertEquals(66666, vorbisSetup.idHeader.bitrateNominal);
|
||||||
|
assertEquals(512, vorbisSetup.idHeader.blockSize0);
|
||||||
|
assertEquals(1024, vorbisSetup.idHeader.blockSize1);
|
||||||
|
assertEquals(2, vorbisSetup.idHeader.channels);
|
||||||
|
assertTrue(vorbisSetup.idHeader.framingFlag);
|
||||||
|
assertEquals(22050, vorbisSetup.idHeader.sampleRate);
|
||||||
|
assertEquals(0, vorbisSetup.idHeader.version);
|
||||||
|
|
||||||
|
assertEquals("Xiph.Org libVorbis I 20030909", vorbisSetup.commentHeader.vendor);
|
||||||
|
assertEquals(1, vorbisSetup.iLogModes);
|
||||||
|
|
||||||
|
assertEquals(data[data.length - 1],
|
||||||
|
vorbisSetup.setupHeaderData[vorbisSetup.setupHeaderData.length - 1]);
|
||||||
|
|
||||||
|
assertFalse(vorbisSetup.modes[0].blockFlag);
|
||||||
|
assertTrue(vorbisSetup.modes[1].blockFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FakeExtractorInput createInput(byte[] data) {
|
||||||
|
return new FakeExtractorInput.Builder().setData(data).setSimulateIOErrors(true)
|
||||||
|
.setSimulateUnknownLength(true).setSimulatePartialReads(true).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sniff(FakeExtractorInput input) throws InterruptedException, IOException {
|
||||||
|
while (true) {
|
||||||
try {
|
try {
|
||||||
vorbisSetup = extractor.readSetupHeaders(extractorInput,
|
return extractor.sniff(input);
|
||||||
new ParsableByteArray(new byte[255 * 255], 0));
|
} catch (SimulatedIOException e) {
|
||||||
|
// Ignore.
|
||||||
assertNotNull(vorbisSetup.idHeader);
|
|
||||||
assertNotNull(vorbisSetup.commentHeader);
|
|
||||||
assertNotNull(vorbisSetup.setupHeaderData);
|
|
||||||
assertNotNull(vorbisSetup.modes);
|
|
||||||
|
|
||||||
assertEquals(45, vorbisSetup.commentHeader.length);
|
|
||||||
assertEquals(30, vorbisSetup.idHeader.data.length);
|
|
||||||
assertEquals(3597, vorbisSetup.setupHeaderData.length);
|
|
||||||
|
|
||||||
assertEquals(-1, vorbisSetup.idHeader.bitrateMax);
|
|
||||||
assertEquals(-1, vorbisSetup.idHeader.bitrateMin);
|
|
||||||
assertEquals(66666, vorbisSetup.idHeader.bitrateNominal);
|
|
||||||
assertEquals(512, vorbisSetup.idHeader.blockSize0);
|
|
||||||
assertEquals(1024, vorbisSetup.idHeader.blockSize1);
|
|
||||||
assertEquals(2, vorbisSetup.idHeader.channels);
|
|
||||||
assertTrue(vorbisSetup.idHeader.framingFlag);
|
|
||||||
assertEquals(22050, vorbisSetup.idHeader.sampleRate);
|
|
||||||
assertEquals(0, vorbisSetup.idHeader.version);
|
|
||||||
|
|
||||||
assertEquals("Xiph.Org libVorbis I 20030909", vorbisSetup.commentHeader.vendor);
|
|
||||||
assertEquals(1, vorbisSetup.iLogModes);
|
|
||||||
|
|
||||||
assertEquals(data[data.length - 1],
|
|
||||||
vorbisSetup.setupHeaderData[vorbisSetup.setupHeaderData.length - 1]);
|
|
||||||
|
|
||||||
assertFalse(vorbisSetup.modes[0].blockFlag);
|
|
||||||
assertTrue(vorbisSetup.modes[1].blockFlag);
|
|
||||||
break;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Log.e(TAG, e.getMessage(), e);
|
|
||||||
extractorInput.resetPeekPosition();
|
|
||||||
exceptionCount++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exceptionCount >= maxExceptions) {
|
}
|
||||||
fail("more than " + maxExceptions + " exceptions thrown");
|
|
||||||
|
private VorbisSetup readSetupHeaders(FakeExtractorInput input)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
return extractor.readSetupHeaders(input, scratch);
|
||||||
|
} catch (SimulatedIOException e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,277 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2015 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.exoplayer.extractor.ogg;
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.C;
|
|
||||||
import com.google.android.exoplayer.extractor.ExtractorInput;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of {@link ExtractorInput} for testing purpose.
|
|
||||||
*/
|
|
||||||
/* package */ class RecordableExtractorInput implements ExtractorInput {
|
|
||||||
|
|
||||||
private byte[] data;
|
|
||||||
private int readPosition;
|
|
||||||
private int writePosition;
|
|
||||||
private int peekPosition;
|
|
||||||
|
|
||||||
private boolean throwExceptionsAtRead = false;
|
|
||||||
private boolean throwExceptionsAtPeek = false;
|
|
||||||
private int numberOfReadsUntilException = 1;
|
|
||||||
private int numberOfPeeksUntilException = 1;
|
|
||||||
private int readCounter;
|
|
||||||
private int peekCounter;
|
|
||||||
private int maxReadExceptions = Integer.MAX_VALUE;
|
|
||||||
private int maxPeekExceptions = Integer.MAX_VALUE;
|
|
||||||
private int readExceptionCounter;
|
|
||||||
private int peekExceptionCounter;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an instance with a initial array of bytes.
|
|
||||||
*
|
|
||||||
* @param data The initial data.
|
|
||||||
* @param writePosition The {@code writePosition} from where to start recording.
|
|
||||||
*/
|
|
||||||
public RecordableExtractorInput(byte[] data, int writePosition) {
|
|
||||||
this.data = data;
|
|
||||||
this.writePosition = writePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an instance with an empty data array with length {@code maxBytes}.
|
|
||||||
*
|
|
||||||
* @param maxBytes the maximal number of bytes this {@code ExtractorInput} can store.
|
|
||||||
*/
|
|
||||||
public RecordableExtractorInput(int maxBytes) {
|
|
||||||
this(new byte[maxBytes], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(byte[] target, int offset, int length) throws IOException, InterruptedException {
|
|
||||||
readFully(target, offset, length);
|
|
||||||
return isEOF() ? C.RESULT_END_OF_INPUT : length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean readFully(byte[] target, int offset, int length, boolean allowEndOfInput)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
readCounter++;
|
|
||||||
if (throwExceptionsAtRead
|
|
||||||
&& readExceptionCounter < maxReadExceptions
|
|
||||||
&& readCounter % numberOfReadsUntilException == 0) {
|
|
||||||
readCounter = 0;
|
|
||||||
numberOfReadsUntilException++;
|
|
||||||
readExceptionCounter++;
|
|
||||||
throw new IOException("deliberately thrown an exception for testing");
|
|
||||||
}
|
|
||||||
if (readPosition + length > writePosition) {
|
|
||||||
if (!allowEndOfInput) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
System.arraycopy(data, readPosition, target, offset, length);
|
|
||||||
readPosition += length;
|
|
||||||
peekPosition = readPosition;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readFully(byte[] target, int offset, int length)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
readFully(target, offset, length, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int skip(int length) throws IOException, InterruptedException {
|
|
||||||
skipFully(length);
|
|
||||||
return isEOF() ? C.RESULT_END_OF_INPUT : length;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isEOF() {
|
|
||||||
return readPosition == writePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean skipFully(int length, boolean allowEndOfInput)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
if (readPosition + length >= writePosition) {
|
|
||||||
if (!allowEndOfInput) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
readPosition += length;
|
|
||||||
peekPosition = readPosition;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void skipFully(int length) throws IOException, InterruptedException {
|
|
||||||
skipFully(length, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean peekFully(byte[] target, int offset, int length, boolean allowEndOfInput)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
peekCounter++;
|
|
||||||
if (throwExceptionsAtPeek
|
|
||||||
&& peekExceptionCounter < maxPeekExceptions
|
|
||||||
&& peekCounter % numberOfPeeksUntilException == 0) {
|
|
||||||
peekCounter = 0;
|
|
||||||
numberOfPeeksUntilException++;
|
|
||||||
peekExceptionCounter++;
|
|
||||||
throw new IOException("deliberately thrown an exception for testing");
|
|
||||||
}
|
|
||||||
if (peekPosition + length > writePosition) {
|
|
||||||
if (!allowEndOfInput) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
System.arraycopy(data, peekPosition, target, offset, length);
|
|
||||||
peekPosition += length;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void peekFully(byte[] target, int offset, int length)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
peekFully(target, offset, length, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean advancePeekPosition(int length, boolean allowEndOfInput)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
if (peekPosition + length >= writePosition) {
|
|
||||||
if (!allowEndOfInput) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
peekPosition += length;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void advancePeekPosition(int length) throws IOException, InterruptedException {
|
|
||||||
advancePeekPosition(length, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resetPeekPosition() {
|
|
||||||
peekPosition = readPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getPeekPosition() {
|
|
||||||
return peekPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getPosition() {
|
|
||||||
return readPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getLength() {
|
|
||||||
return writePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Records the {@code bytes}.
|
|
||||||
*
|
|
||||||
* @param bytes the bytes to record.
|
|
||||||
*/
|
|
||||||
public void record(final byte[] bytes) {
|
|
||||||
System.arraycopy(bytes, 0, data, writePosition, bytes.length);
|
|
||||||
writePosition += bytes.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Records a single byte. **/
|
|
||||||
public void record(byte b) {
|
|
||||||
record(new byte[] {b});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a byte array with length {@code length} with ascending values starting from 0 (zero).
|
|
||||||
*
|
|
||||||
* @param length the length of the array.
|
|
||||||
* @return an array of bytes with ascending values.
|
|
||||||
*/
|
|
||||||
public static byte[] getBytesGrowingValues(int length) {
|
|
||||||
return fillBytesGrowingValues(new byte[length], length, (byte) 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a byte array with length {@code length} with ascending values starting
|
|
||||||
* from {@code startValue}.
|
|
||||||
*
|
|
||||||
* @param length the length of the array.
|
|
||||||
* @param startValue the value from which to start.
|
|
||||||
* @return an array of bytes with ascending values starting from {@code startValue}.
|
|
||||||
*/
|
|
||||||
public static byte[] getBytesGrowingValues(int length, byte startValue) {
|
|
||||||
return fillBytesGrowingValues(new byte[length], length, startValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills the byte array passed as argument with ascending values.
|
|
||||||
*
|
|
||||||
* @param bytes the byte array to fill with values.
|
|
||||||
* @param limit the number of bytes to set in the array.
|
|
||||||
* @param startValue the startValue from which the values in the array have to start.
|
|
||||||
*/
|
|
||||||
public static byte[] fillBytesGrowingValues(byte[] bytes, int limit, byte startValue) {
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
if (i < limit) {
|
|
||||||
bytes[i] = (byte) ((i + startValue) % 255);
|
|
||||||
} else {
|
|
||||||
bytes[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxReadExceptions(int maxReadExceptions) {
|
|
||||||
this.maxReadExceptions = maxReadExceptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxPeekExceptions(int maxPeekExceptions) {
|
|
||||||
this.maxPeekExceptions = maxPeekExceptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNumberOfReadsUntilException(int numberOfReadsUntilException) {
|
|
||||||
this.numberOfReadsUntilException = numberOfReadsUntilException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNumberOfPeeksUntilException(int numberOfPeeksUntilException) {
|
|
||||||
this.numberOfPeeksUntilException = numberOfPeeksUntilException;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doThrowExceptionsAtRead(boolean throwExceptionsAtRead) {
|
|
||||||
this.throwExceptionsAtRead = throwExceptionsAtRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doThrowExceptionsAtPeek(boolean throwExceptionsAtPeek) {
|
|
||||||
this.throwExceptionsAtPeek = throwExceptionsAtPeek;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2015 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.google.android.exoplayer.extractor.ogg;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link RecordableOggExtractorInput} with convenient methods to record an OGG byte stream.
|
|
||||||
*/
|
|
||||||
/* package */ final class RecordableOggExtractorInput extends RecordableExtractorInput {
|
|
||||||
|
|
||||||
public static final byte STREAM_REVISION = 0x00;
|
|
||||||
|
|
||||||
private long pageSequenceCounter;
|
|
||||||
|
|
||||||
public RecordableOggExtractorInput(byte[] data, int writeOffset) {
|
|
||||||
super(data, writeOffset);
|
|
||||||
pageSequenceCounter = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordableOggExtractorInput(int maxBytes) {
|
|
||||||
this(new byte[maxBytes], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Syntax sugar to make tests more readable.
|
|
||||||
*
|
|
||||||
* @param laces the laces to record to the data.
|
|
||||||
*/
|
|
||||||
protected void recordOggLaces(final byte[] laces) {
|
|
||||||
record(laces);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Syntax sugar to make tests more readable.
|
|
||||||
*
|
|
||||||
* @param packet the packet bytes to record to the data.
|
|
||||||
*/
|
|
||||||
protected void recordOggPacket(final byte[] packet) {
|
|
||||||
record(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void recordOggHeader(final byte headerType, final long granule,
|
|
||||||
final byte pageSegmentCount) {
|
|
||||||
record((byte) 0x4F); // O
|
|
||||||
record((byte) 0x67); // g
|
|
||||||
record((byte) 0x67); // g
|
|
||||||
record((byte) 0x53); // S
|
|
||||||
record(STREAM_REVISION);
|
|
||||||
record(headerType);
|
|
||||||
recordGranulePosition(granule);
|
|
||||||
record((byte) 0x00); // LSB of data serial number
|
|
||||||
record((byte) 0x10);
|
|
||||||
record((byte) 0x00);
|
|
||||||
record((byte) 0x00); // MSB of data serial number
|
|
||||||
recordPageSequenceCounter();
|
|
||||||
record((byte) 0x00); // LSB of page checksum
|
|
||||||
record((byte) 0x00);
|
|
||||||
record((byte) 0x00);
|
|
||||||
record((byte) 0x00); // MSB of page checksum
|
|
||||||
record(pageSegmentCount); // 0 - 255
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void recordGranulePosition(long granule) {
|
|
||||||
record((byte) (granule & 0xFF));
|
|
||||||
record((byte) ((granule >> 8) & 0xFF));
|
|
||||||
record((byte) ((granule >> 16) & 0xFF));
|
|
||||||
record((byte) ((granule >> 24) & 0xFF));
|
|
||||||
record((byte) ((granule >> 32) & 0xFF));
|
|
||||||
record((byte) ((granule >> 40) & 0xFF));
|
|
||||||
record((byte) ((granule >> 48) & 0xFF));
|
|
||||||
record((byte) ((granule >> 56) & 0xFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void recordPageSequenceCounter() {
|
|
||||||
record((byte) (pageSequenceCounter & 0xFF));
|
|
||||||
record((byte) ((pageSequenceCounter >> 8) & 0xFF));
|
|
||||||
record((byte) ((pageSequenceCounter >> 16) & 0xFF));
|
|
||||||
record((byte) ((pageSequenceCounter++ >> 24) & 0xFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -15,11 +15,42 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer.extractor.ogg;
|
package com.google.android.exoplayer.extractor.ogg;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.testutil.TestUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides ogg/vorbis test data in bytes for unit tests.
|
* Provides ogg/vorbis test data in bytes for unit tests.
|
||||||
*/
|
*/
|
||||||
/* package */ final class TestData {
|
/* package */ final class TestData {
|
||||||
|
|
||||||
|
public static byte[] buildOggHeader(int headerType, long granule, int pageSequenceCounter,
|
||||||
|
int pageSegmentCount) {
|
||||||
|
return TestUtil.createByteArray(
|
||||||
|
0x4F, 0x67, 0x67, 0x53, // Oggs.
|
||||||
|
0x00, // Stream revision.
|
||||||
|
headerType,
|
||||||
|
(int) (granule >> 0) & 0xFF,
|
||||||
|
(int) (granule >> 8) & 0xFF,
|
||||||
|
(int) (granule >> 16) & 0xFF,
|
||||||
|
(int) (granule >> 24) & 0xFF,
|
||||||
|
(int) (granule >> 32) & 0xFF,
|
||||||
|
(int) (granule >> 40) & 0xFF,
|
||||||
|
(int) (granule >> 48) & 0xFF,
|
||||||
|
(int) (granule >> 56) & 0xFF,
|
||||||
|
0x00, // LSB of data serial number.
|
||||||
|
0x10,
|
||||||
|
0x00,
|
||||||
|
0x00, // MSB of data serial number.
|
||||||
|
(pageSequenceCounter >> 0) & 0xFF,
|
||||||
|
(pageSequenceCounter >> 8) & 0xFF,
|
||||||
|
(pageSequenceCounter >> 16) & 0xFF,
|
||||||
|
(pageSequenceCounter >> 24) & 0xFF,
|
||||||
|
0x00, // LSB of page checksum.
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00, // MSB of page checksum.
|
||||||
|
pageSegmentCount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initial two pages of bytes which by spec contain the three vorbis header packets:
|
* Returns the initial two pages of bytes which by spec contain the three vorbis header packets:
|
||||||
* identification, comment and setup header.
|
* identification, comment and setup header.
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import java.io.IOException;
|
||||||
/**
|
/**
|
||||||
* A fake {@link ExtractorInput} capable of simulating various scenarios.
|
* A fake {@link ExtractorInput} capable of simulating various scenarios.
|
||||||
* <p>
|
* <p>
|
||||||
* Read, skip and peek errors can be simulated using {@link Builder#setSimulateIOErrors)}. When
|
* Read, skip and peek errors can be simulated using {@link Builder#setSimulateIOErrors}. When
|
||||||
* enabled each read and skip will throw a {@link SimulatedIOException} unless one has already been
|
* enabled each read and skip will throw a {@link SimulatedIOException} unless one has already been
|
||||||
* thrown from the current position. Each peek will throw {@link SimulatedIOException} unless one
|
* thrown from the current position. Each peek will throw {@link SimulatedIOException} unless one
|
||||||
* has already been thrown from the current peek position. When a {@link SimulatedIOException} is
|
* has already been thrown from the current peek position. When a {@link SimulatedIOException} is
|
||||||
|
|
@ -43,7 +43,7 @@ import java.io.IOException;
|
||||||
* bytes then it will be fully satisfied, since it has the same target position of 10.
|
* bytes then it will be fully satisfied, since it has the same target position of 10.
|
||||||
* <p>
|
* <p>
|
||||||
* Unknown data length can be simulated using {@link Builder#setSimulateUnknownLength}. When enabled
|
* Unknown data length can be simulated using {@link Builder#setSimulateUnknownLength}. When enabled
|
||||||
* {@link getLength()} will return {@link C#LENGTH_UNBOUNDED} rather than the length of the data.
|
* {@link #getLength()} will return {@link C#LENGTH_UNBOUNDED} rather than the length of the data.
|
||||||
*/
|
*/
|
||||||
public final class FakeExtractorInput implements ExtractorInput {
|
public final class FakeExtractorInput implements ExtractorInput {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,10 @@ public class TestUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] buildTestData(int length, int seed) {
|
public static byte[] buildTestData(int length, int seed) {
|
||||||
Random random = new Random(seed);
|
return buildTestData(length, new Random(seed));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] buildTestData(int length, Random random) {
|
||||||
byte[] source = new byte[length];
|
byte[] source = new byte[length];
|
||||||
random.nextBytes(source);
|
random.nextBytes(source);
|
||||||
return source;
|
return source;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue