mirror of
https://github.com/samsonjs/media.git
synced 2026-04-21 13:55:47 +00:00
Clean up + optimize ParsableByteArray.
This commit is contained in:
parent
9092fad8e8
commit
508e13e0bd
11 changed files with 241 additions and 135 deletions
|
|
@ -36,12 +36,12 @@ import com.google.android.exoplayer.util.Util;
|
|||
long basePosition = position + mpegAudioHeader.frameSize;
|
||||
|
||||
// Read the VBRI header.
|
||||
frame.skip(32);
|
||||
frame.skipBytes(32);
|
||||
int headerData = frame.readInt();
|
||||
if (headerData != VBRI_HEADER) {
|
||||
return null;
|
||||
}
|
||||
frame.skip(10);
|
||||
frame.skipBytes(10);
|
||||
int numFrames = frame.readInt();
|
||||
if (numFrames <= 0) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ import com.google.android.exoplayer.util.Util;
|
|||
xingBase = 9;
|
||||
}
|
||||
}
|
||||
frame.skip(4 + xingBase);
|
||||
frame.skipBytes(4 + xingBase);
|
||||
int headerData = frame.readInt();
|
||||
if (headerData != XING_HEADER && headerData != INFO_HEADER) {
|
||||
return null;
|
||||
|
|
@ -80,7 +80,7 @@ import com.google.android.exoplayer.util.Util;
|
|||
long sizeBytes = frame.readUnsignedIntToInt();
|
||||
|
||||
// Read table-of-contents as (flags & 4) == 4.
|
||||
frame.skip(1);
|
||||
frame.skipBytes(1);
|
||||
long[] tableOfContents = new long[99];
|
||||
for (int i = 0; i < 99; i++) {
|
||||
tableOfContents[i] = frame.readUnsignedByte();
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ import java.util.List;
|
|||
int remainingSamplesPerChunkChanges = stsc.readUnsignedIntToInt() - 1;
|
||||
Assertions.checkState(stsc.readInt() == 1, "stsc first chunk must be 1");
|
||||
int samplesPerChunk = stsc.readUnsignedIntToInt();
|
||||
stsc.skip(4); // Skip the sample description index.
|
||||
stsc.skipBytes(4); // Skip the sample description index.
|
||||
int nextSamplesPerChunkChangeChunkIndex = -1;
|
||||
if (remainingSamplesPerChunkChanges > 0) {
|
||||
// Store the chunk index when the samples-per-chunk will next change.
|
||||
|
|
@ -220,7 +220,7 @@ import java.util.List;
|
|||
// Change the samples-per-chunk if required.
|
||||
if (chunkIndex == nextSamplesPerChunkChangeChunkIndex) {
|
||||
samplesPerChunk = stsc.readUnsignedIntToInt();
|
||||
stsc.skip(4); // Skip the sample description index.
|
||||
stsc.skipBytes(4); // Skip the sample description index.
|
||||
remainingSamplesPerChunkChanges--;
|
||||
if (remainingSamplesPerChunkChanges > 0) {
|
||||
nextSamplesPerChunkChangeChunkIndex = stsc.readUnsignedIntToInt() - 1;
|
||||
|
|
@ -260,7 +260,7 @@ import java.util.List;
|
|||
int fullAtom = mvhd.readInt();
|
||||
int version = Atom.parseFullAtomVersion(fullAtom);
|
||||
|
||||
mvhd.skip(version == 0 ? 8 : 16);
|
||||
mvhd.skipBytes(version == 0 ? 8 : 16);
|
||||
|
||||
return mvhd.readUnsignedInt();
|
||||
}
|
||||
|
|
@ -276,10 +276,10 @@ import java.util.List;
|
|||
int fullAtom = tkhd.readInt();
|
||||
int version = Atom.parseFullAtomVersion(fullAtom);
|
||||
|
||||
tkhd.skip(version == 0 ? 8 : 16);
|
||||
tkhd.skipBytes(version == 0 ? 8 : 16);
|
||||
|
||||
int trackId = tkhd.readInt();
|
||||
tkhd.skip(4);
|
||||
tkhd.skipBytes(4);
|
||||
|
||||
boolean durationUnknown = true;
|
||||
int durationPosition = tkhd.getPosition();
|
||||
|
|
@ -292,7 +292,7 @@ import java.util.List;
|
|||
}
|
||||
long duration;
|
||||
if (durationUnknown) {
|
||||
tkhd.skip(durationByteCount);
|
||||
tkhd.skipBytes(durationByteCount);
|
||||
duration = -1;
|
||||
} else {
|
||||
duration = version == 0 ? tkhd.readUnsignedInt() : tkhd.readUnsignedLongToLong();
|
||||
|
|
@ -323,7 +323,7 @@ import java.util.List;
|
|||
int fullAtom = mdhd.readInt();
|
||||
int version = Atom.parseFullAtomVersion(fullAtom);
|
||||
|
||||
mdhd.skip(version == 0 ? 8 : 16);
|
||||
mdhd.skipBytes(version == 0 ? 8 : 16);
|
||||
return mdhd.readUnsignedInt();
|
||||
}
|
||||
|
||||
|
|
@ -365,11 +365,11 @@ import java.util.List;
|
|||
int position, int size, long durationUs) {
|
||||
parent.setPosition(position + Atom.HEADER_SIZE);
|
||||
|
||||
parent.skip(24);
|
||||
parent.skipBytes(24);
|
||||
int width = parent.readUnsignedShort();
|
||||
int height = parent.readUnsignedShort();
|
||||
float pixelWidthHeightRatio = 1;
|
||||
parent.skip(50);
|
||||
parent.skipBytes(50);
|
||||
|
||||
List<byte[]> initializationData = null;
|
||||
TrackEncryptionBox trackEncryptionBox = null;
|
||||
|
|
@ -434,7 +434,7 @@ import java.util.List;
|
|||
if (childAtomType == Atom.TYPE_frma) {
|
||||
parent.readInt(); // dataFormat.
|
||||
} else if (childAtomType == Atom.TYPE_schm) {
|
||||
parent.skip(4);
|
||||
parent.skipBytes(4);
|
||||
parent.readInt(); // schemeType. Expect cenc
|
||||
parent.readInt(); // schemeVersion. Expect 0x00010000
|
||||
} else if (childAtomType == Atom.TYPE_schi) {
|
||||
|
|
@ -461,7 +461,7 @@ import java.util.List;
|
|||
int childAtomSize = parent.readInt();
|
||||
int childAtomType = parent.readInt();
|
||||
if (childAtomType == Atom.TYPE_tenc) {
|
||||
parent.skip(4);
|
||||
parent.skipBytes(4);
|
||||
int firstInt = parent.readInt();
|
||||
boolean defaultIsEncrypted = (firstInt >> 8) == 1;
|
||||
int defaultInitVectorSize = firstInt & 0xFF;
|
||||
|
|
@ -479,10 +479,10 @@ import java.util.List;
|
|||
long durationUs) {
|
||||
parent.setPosition(position + Atom.HEADER_SIZE);
|
||||
|
||||
parent.skip(24);
|
||||
parent.skipBytes(24);
|
||||
int width = parent.readUnsignedShort();
|
||||
int height = parent.readUnsignedShort();
|
||||
parent.skip(50);
|
||||
parent.skipBytes(50);
|
||||
|
||||
List<byte[]> initializationData = new ArrayList<byte[]>(1);
|
||||
int childPosition = parent.getPosition();
|
||||
|
|
@ -505,10 +505,10 @@ import java.util.List;
|
|||
private static Pair<MediaFormat, TrackEncryptionBox> parseAudioSampleEntry(
|
||||
ParsableByteArray parent, int atomType, int position, int size, long durationUs) {
|
||||
parent.setPosition(position + Atom.HEADER_SIZE);
|
||||
parent.skip(16);
|
||||
parent.skipBytes(16);
|
||||
int channelCount = parent.readUnsignedShort();
|
||||
int sampleSize = parent.readUnsignedShort();
|
||||
parent.skip(4);
|
||||
parent.skipBytes(4);
|
||||
int sampleRate = parent.readUnsignedFixedPoint1616();
|
||||
int bitrate = MediaFormat.NO_VALUE;
|
||||
|
||||
|
|
@ -571,34 +571,34 @@ import java.util.List;
|
|||
private static byte[] parseEsdsFromParent(ParsableByteArray parent, int position) {
|
||||
parent.setPosition(position + Atom.HEADER_SIZE + 4);
|
||||
// Start of the ES_Descriptor (defined in 14496-1)
|
||||
parent.skip(1); // ES_Descriptor tag
|
||||
parent.skipBytes(1); // ES_Descriptor tag
|
||||
int varIntByte = parent.readUnsignedByte();
|
||||
while (varIntByte > 127) {
|
||||
varIntByte = parent.readUnsignedByte();
|
||||
}
|
||||
parent.skip(2); // ES_ID
|
||||
parent.skipBytes(2); // ES_ID
|
||||
|
||||
int flags = parent.readUnsignedByte();
|
||||
if ((flags & 0x80 /* streamDependenceFlag */) != 0) {
|
||||
parent.skip(2);
|
||||
parent.skipBytes(2);
|
||||
}
|
||||
if ((flags & 0x40 /* URL_Flag */) != 0) {
|
||||
parent.skip(parent.readUnsignedShort());
|
||||
parent.skipBytes(parent.readUnsignedShort());
|
||||
}
|
||||
if ((flags & 0x20 /* OCRstreamFlag */) != 0) {
|
||||
parent.skip(2);
|
||||
parent.skipBytes(2);
|
||||
}
|
||||
|
||||
// Start of the DecoderConfigDescriptor (defined in 14496-1)
|
||||
parent.skip(1); // DecoderConfigDescriptor tag
|
||||
parent.skipBytes(1); // DecoderConfigDescriptor tag
|
||||
varIntByte = parent.readUnsignedByte();
|
||||
while (varIntByte > 127) {
|
||||
varIntByte = parent.readUnsignedByte();
|
||||
}
|
||||
parent.skip(13);
|
||||
parent.skipBytes(13);
|
||||
|
||||
// Start of AudioSpecificConfig (defined in 14496-3)
|
||||
parent.skip(1); // AudioSpecificConfig tag
|
||||
parent.skipBytes(1); // AudioSpecificConfig tag
|
||||
varIntByte = parent.readUnsignedByte();
|
||||
int varInt = varIntByte & 0x7F;
|
||||
while (varIntByte > 127) {
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||
int fullAtom = saiz.readInt();
|
||||
int flags = Atom.parseFullAtomFlags(fullAtom);
|
||||
if ((flags & 0x01) == 1) {
|
||||
saiz.skip(8);
|
||||
saiz.skipBytes(8);
|
||||
}
|
||||
int defaultSampleInfoSize = saiz.readUnsignedByte();
|
||||
|
||||
|
|
@ -379,9 +379,9 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||
int fullAtom = tfhd.readInt();
|
||||
int flags = Atom.parseFullAtomFlags(fullAtom);
|
||||
|
||||
tfhd.skip(4); // trackId
|
||||
tfhd.skipBytes(4); // trackId
|
||||
if ((flags & 0x01 /* base_data_offset_present */) != 0) {
|
||||
tfhd.skip(8);
|
||||
tfhd.skipBytes(8);
|
||||
}
|
||||
|
||||
int defaultSampleDescriptionIndex =
|
||||
|
|
@ -427,7 +427,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||
|
||||
int sampleCount = trun.readUnsignedIntToInt();
|
||||
if ((flags & 0x01 /* data_offset_present */) != 0) {
|
||||
trun.skip(4);
|
||||
trun.skipBytes(4);
|
||||
}
|
||||
|
||||
boolean firstSampleFlagsPresent = (flags & 0x04 /* first_sample_flags_present */) != 0;
|
||||
|
|
@ -528,7 +528,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||
int fullAtom = atom.readInt();
|
||||
int version = Atom.parseFullAtomVersion(fullAtom);
|
||||
|
||||
atom.skip(4);
|
||||
atom.skipBytes(4);
|
||||
long timescale = atom.readUnsignedInt();
|
||||
long earliestPresentationTime;
|
||||
long offset = inputPosition;
|
||||
|
|
@ -540,7 +540,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||
offset += atom.readUnsignedLongToLong();
|
||||
}
|
||||
|
||||
atom.skip(2);
|
||||
atom.skipBytes(2);
|
||||
|
||||
int referenceCount = atom.readUnsignedShort();
|
||||
int[] sizes = new int[referenceCount];
|
||||
|
|
@ -569,7 +569,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||
timeUs = Util.scaleLargeTimestamp(time, C.MICROS_PER_SECOND, timescale);
|
||||
durationsUs[i] = timeUs - timesUs[i];
|
||||
|
||||
atom.skip(4);
|
||||
atom.skipBytes(4);
|
||||
offset += sizes[i];
|
||||
}
|
||||
|
||||
|
|
@ -670,7 +670,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
|||
}
|
||||
// Write the subsample encryption data.
|
||||
int subsampleCount = sampleEncryptionData.readUnsignedShort();
|
||||
sampleEncryptionData.skip(-2);
|
||||
sampleEncryptionData.skipBytes(-2);
|
||||
int subsampleDataLength = 2 + 6 * subsampleCount;
|
||||
trackOutput.sampleData(sampleEncryptionData, subsampleDataLength);
|
||||
return 1 + vectorSize + subsampleDataLength;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
|||
@Override
|
||||
public void consume(ParsableByteArray seiBuffer, long pesTimeUs, boolean startOfPacket) {
|
||||
// Skip the NAL prefix and type.
|
||||
seiBuffer.skip(4);
|
||||
seiBuffer.skipBytes(4);
|
||||
|
||||
int b;
|
||||
while (seiBuffer.bytesLeft() > 1 /* last byte will be rbsp_trailing_bits */) {
|
||||
|
|
@ -58,7 +58,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
|||
output.sampleData(seiBuffer, payloadSize);
|
||||
output.sampleMetadata(pesTimeUs, C.SAMPLE_FLAG_SYNC, payloadSize, 0, null);
|
||||
} else {
|
||||
seiBuffer.skip(payloadSize);
|
||||
seiBuffer.skipBytes(payloadSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public final class TsExtractor implements Extractor {
|
|||
// Skip the adaptation field.
|
||||
if (adaptationFieldExists) {
|
||||
int adaptationFieldLength = tsPacketBuffer.readUnsignedByte();
|
||||
tsPacketBuffer.skip(adaptationFieldLength);
|
||||
tsPacketBuffer.skipBytes(adaptationFieldLength);
|
||||
}
|
||||
|
||||
// Read the payload.
|
||||
|
|
@ -172,7 +172,7 @@ public final class TsExtractor implements Extractor {
|
|||
// Skip pointer.
|
||||
if (payloadUnitStartIndicator) {
|
||||
int pointerField = data.readUnsignedByte();
|
||||
data.skip(pointerField);
|
||||
data.skipBytes(pointerField);
|
||||
}
|
||||
|
||||
data.readBytes(patScratch, 3);
|
||||
|
|
@ -180,7 +180,7 @@ public final class TsExtractor implements Extractor {
|
|||
int sectionLength = patScratch.readBits(12);
|
||||
// transport_stream_id (16), reserved (2), version_number (5), current_next_indicator (1),
|
||||
// section_number (8), last_section_number (8)
|
||||
data.skip(5);
|
||||
data.skipBytes(5);
|
||||
|
||||
int programCount = (sectionLength - 9) / 4;
|
||||
for (int i = 0; i < programCount; i++) {
|
||||
|
|
@ -212,7 +212,7 @@ public final class TsExtractor implements Extractor {
|
|||
// Skip pointer.
|
||||
if (payloadUnitStartIndicator) {
|
||||
int pointerField = data.readUnsignedByte();
|
||||
data.skip(pointerField);
|
||||
data.skipBytes(pointerField);
|
||||
}
|
||||
|
||||
data.readBytes(pmtScratch, 3);
|
||||
|
|
@ -222,14 +222,14 @@ public final class TsExtractor implements Extractor {
|
|||
// program_number (16), reserved (2), version_number (5), current_next_indicator (1),
|
||||
// section_number (8), last_section_number (8), reserved (3), PCR_PID (13)
|
||||
// Skip the rest of the PMT header.
|
||||
data.skip(7);
|
||||
data.skipBytes(7);
|
||||
|
||||
data.readBytes(pmtScratch, 2);
|
||||
pmtScratch.skipBits(4);
|
||||
int programInfoLength = pmtScratch.readBits(12);
|
||||
|
||||
// Skip the descriptors.
|
||||
data.skip(programInfoLength);
|
||||
data.skipBytes(programInfoLength);
|
||||
|
||||
int entriesSize = sectionLength - 9 /* Size of the rest of the fields before descriptors */
|
||||
- programInfoLength - 4 /* CRC size */;
|
||||
|
|
@ -242,7 +242,7 @@ public final class TsExtractor implements Extractor {
|
|||
int esInfoLength = pmtScratch.readBits(12);
|
||||
|
||||
// Skip the descriptors.
|
||||
data.skip(esInfoLength);
|
||||
data.skipBytes(esInfoLength);
|
||||
entriesSize -= esInfoLength + 5;
|
||||
|
||||
if (streamReaders.get(streamType) != null) {
|
||||
|
|
@ -341,7 +341,7 @@ public final class TsExtractor implements Extractor {
|
|||
while (data.bytesLeft() > 0) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_HEADER:
|
||||
data.skip(data.bytesLeft());
|
||||
data.skipBytes(data.bytesLeft());
|
||||
break;
|
||||
case STATE_READING_HEADER:
|
||||
if (continueRead(data, pesScratch.getData(), HEADER_SIZE)) {
|
||||
|
|
@ -398,7 +398,7 @@ public final class TsExtractor implements Extractor {
|
|||
if (bytesToRead <= 0) {
|
||||
return true;
|
||||
} else if (target == null) {
|
||||
source.skip(bytesToRead);
|
||||
source.skipBytes(bytesToRead);
|
||||
} else {
|
||||
source.readBytes(target, bytesRead, bytesToRead);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class Id3Parser implements MetadataParser<Map<String, Object>> {
|
|||
}
|
||||
|
||||
// Skip frame flags.
|
||||
id3Data.skip(2);
|
||||
id3Data.skipBytes(2);
|
||||
// Check Frame ID == TXXX.
|
||||
if (frameId0 == 'T' && frameId1 == 'X' && frameId2 == 'X' && frameId3 == 'X') {
|
||||
int encoding = id3Data.readUnsignedByte();
|
||||
|
|
@ -168,7 +168,7 @@ public class Id3Parser implements MetadataParser<Map<String, Object>> {
|
|||
throw new ParserException(String.format(
|
||||
"Unexpected ID3 file identifier, expected \"ID3\", actual \"%c%c%c\".", id1, id2, id3));
|
||||
}
|
||||
id3Buffer.skip(2); // Skip version.
|
||||
id3Buffer.skipBytes(2); // Skip version.
|
||||
|
||||
int flags = id3Buffer.readUnsignedByte();
|
||||
int id3Size = id3Buffer.readSynchSafeInt();
|
||||
|
|
@ -177,7 +177,7 @@ public class Id3Parser implements MetadataParser<Map<String, Object>> {
|
|||
if ((flags & 0x2) != 0) {
|
||||
int extendedHeaderSize = id3Buffer.readSynchSafeInt();
|
||||
if (extendedHeaderSize > 4) {
|
||||
id3Buffer.skip(extendedHeaderSize - 4);
|
||||
id3Buffer.skipBytes(extendedHeaderSize - 4);
|
||||
}
|
||||
id3Size -= extendedHeaderSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public final class H264Util {
|
|||
public static byte[] parseChildNalUnit(ParsableByteArray atom) {
|
||||
int length = atom.readUnsignedShort();
|
||||
int offset = atom.getPosition();
|
||||
atom.skip(length);
|
||||
atom.skipBytes(length);
|
||||
return CodecSpecificDataUtil.buildNalUnit(atom.data, offset, length);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,9 +123,7 @@ public final class ParsableByteArray {
|
|||
* @throws IllegalArgumentException Thrown if the new position is neither in nor at the end of the
|
||||
* array.
|
||||
*/
|
||||
// TODO: Rename to skipBytes so that it's clearer how much data is being skipped in code where
|
||||
// both ParsableBitArray and ParsableByteArray are in use.
|
||||
public void skip(int bytes) {
|
||||
public void skipBytes(int bytes) {
|
||||
setPosition(position + bytes);
|
||||
}
|
||||
|
||||
|
|
@ -136,8 +134,6 @@ public final class ParsableByteArray {
|
|||
* @param bitArray The {@link ParsableBitArray} into which the bytes should be read.
|
||||
* @param length The number of bytes to write.
|
||||
*/
|
||||
// TODO: It's possible to have bitArray directly index into the same array as is being wrapped
|
||||
// by this instance. Decide whether it's worth doing this.
|
||||
public void readBytes(ParsableBitArray bitArray, int length) {
|
||||
readBytes(bitArray.getData(), 0, length);
|
||||
bitArray.setPosition(0);
|
||||
|
|
@ -165,52 +161,55 @@ public final class ParsableByteArray {
|
|||
|
||||
/** Reads the next byte as an unsigned value. */
|
||||
public int readUnsignedByte() {
|
||||
int result = shiftIntoInt(data, position, 1);
|
||||
position += 1;
|
||||
return result;
|
||||
return (data[position++] & 0xFF);
|
||||
}
|
||||
|
||||
/** Reads the next two bytes as an unsigned value. */
|
||||
public int readUnsignedShort() {
|
||||
int result = shiftIntoInt(data, position, 2);
|
||||
position += 2;
|
||||
return result;
|
||||
return (data[position++] & 0xFF) << 8
|
||||
| (data[position++] & 0xFF);
|
||||
}
|
||||
|
||||
/** Reads the next three bytes as an unsigned value. */
|
||||
public int readUnsignedInt24() {
|
||||
int result = shiftIntoInt(data, position, 3);
|
||||
position += 3;
|
||||
return result;
|
||||
return (data[position++] & 0xFF) << 16
|
||||
| (data[position++] & 0xFF) << 8
|
||||
| (data[position++] & 0xFF);
|
||||
}
|
||||
|
||||
/** Reads the next four bytes as an unsigned value. */
|
||||
public long readUnsignedInt() {
|
||||
long result = shiftIntoLong(data, position, 4);
|
||||
position += 4;
|
||||
return result;
|
||||
return (data[position++] & 0xFFL) << 24
|
||||
| (data[position++] & 0xFFL) << 16
|
||||
| (data[position++] & 0xFFL) << 8
|
||||
| (data[position++] & 0xFFL);
|
||||
}
|
||||
|
||||
/** Reads the next four bytes as a signed value. */
|
||||
public int readInt() {
|
||||
// shiftIntoInt inlined as performance optimization.
|
||||
return (data[position++] & 0xFF) << 24
|
||||
| (data[position++] & 0xFF) << 16
|
||||
| (data[position++] & 0xFF) << 8
|
||||
| data[position++] & 0xFF;
|
||||
| (data[position++] & 0xFF);
|
||||
}
|
||||
|
||||
/** Reads the next eight bytes as a signed value. */
|
||||
public long readLong() {
|
||||
long result = shiftIntoLong(data, position, 8);
|
||||
position += 8;
|
||||
return result;
|
||||
return (data[position++] & 0xFFL) << 56
|
||||
| (data[position++] & 0xFFL) << 48
|
||||
| (data[position++] & 0xFFL) << 40
|
||||
| (data[position++] & 0xFFL) << 32
|
||||
| (data[position++] & 0xFFL) << 24
|
||||
| (data[position++] & 0xFFL) << 16
|
||||
| (data[position++] & 0xFFL) << 8
|
||||
| (data[position++] & 0xFFL);
|
||||
}
|
||||
|
||||
/** Reads the next four bytes, returning the integer portion of the fixed point 16.16 integer. */
|
||||
public int readUnsignedFixedPoint1616() {
|
||||
int result = shiftIntoInt(data, position, 2);
|
||||
position += 4;
|
||||
int result = (data[position++] & 0xFF) << 8
|
||||
| (data[position++] & 0xFF);
|
||||
position += 2; // Skip the non-integer portion.
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -233,16 +232,12 @@ public final class ParsableByteArray {
|
|||
/**
|
||||
* Reads the next four bytes as an unsigned integer into an integer, if the top bit is a zero.
|
||||
*
|
||||
* @throws IllegalArgumentException Thrown if the top bit of the input data is set.
|
||||
* @throws IllegalStateException Thrown if the top bit of the input data is set.
|
||||
*/
|
||||
public int readUnsignedIntToInt() {
|
||||
// shiftIntoInt inlined as performance optimization.
|
||||
final int result = (data[position++] & 0xFF) << 24
|
||||
| (data[position++] & 0xFF) << 16
|
||||
| (data[position++] & 0xFF) << 8
|
||||
| data[position++] & 0xFF;
|
||||
int result = readInt();
|
||||
if (result < 0) {
|
||||
throw new IllegalArgumentException("Top bit not zero: " + result);
|
||||
throw new IllegalStateException("Top bit not zero: " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -250,33 +245,12 @@ public final class ParsableByteArray {
|
|||
/**
|
||||
* Reads the next eight bytes as an unsigned long into a long, if the top bit is a zero.
|
||||
*
|
||||
* @throws IllegalArgumentException Thrown if the top bit of the input data is set.
|
||||
* @throws IllegalStateException Thrown if the top bit of the input data is set.
|
||||
*/
|
||||
public long readUnsignedLongToLong() {
|
||||
long result = shiftIntoLong(data, position, 8);
|
||||
position += 8;
|
||||
long result = readLong();
|
||||
if (result < 0) {
|
||||
throw new IllegalArgumentException("Top bit not zero: " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reads {@code length} bytes into an int at {@code offset} in {@code bytes}. */
|
||||
private static int shiftIntoInt(byte[] bytes, int offset, int length) {
|
||||
int result = 0xFF & bytes[offset];
|
||||
for (int i = offset + 1; i < offset + length; i++) {
|
||||
result <<= 8;
|
||||
result |= 0xFF & bytes[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reads {@code length} bytes into a long at {@code offset} in {@code bytes}. */
|
||||
private static long shiftIntoLong(byte[] bytes, int offset, int length) {
|
||||
long result = 0xFF & bytes[offset];
|
||||
for (int i = offset + 1; i < offset + length; i++) {
|
||||
result <<= 8;
|
||||
result |= 0xFF & bytes[i];
|
||||
throw new IllegalStateException("Top bit not zero: " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class UrlTemplateTest extends TestCase {
|
|||
String template = "$IllegalId$";
|
||||
try {
|
||||
UrlTemplate.compile(template);
|
||||
assertTrue(false);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer.util;
|
|||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
|
|
@ -24,49 +25,176 @@ import java.util.Arrays;
|
|||
*/
|
||||
public class ParsableByteArrayTest extends TestCase {
|
||||
|
||||
private static final byte[] ARRAY_ELEMENTS =
|
||||
private static final byte[] TEST_DATA =
|
||||
new byte[] {0x0F, (byte) 0xFF, (byte) 0x42, (byte) 0x0F, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
private ParsableByteArray parsableByteArray;
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
parsableByteArray = new ParsableByteArray(ARRAY_ELEMENTS.length);
|
||||
System.arraycopy(ARRAY_ELEMENTS, 0, parsableByteArray.data, 0, ARRAY_ELEMENTS.length);
|
||||
private static ParsableByteArray getTestDataArray() {
|
||||
ParsableByteArray testArray = new ParsableByteArray(TEST_DATA.length);
|
||||
System.arraycopy(TEST_DATA, 0, testArray.data, 0, TEST_DATA.length);
|
||||
return testArray;
|
||||
}
|
||||
|
||||
public void testReadInt() {
|
||||
// When reading a signed integer
|
||||
int value = parsableByteArray.readInt();
|
||||
|
||||
// Then the read value is equal to the array elements interpreted as an int.
|
||||
assertEquals((0xFF & ARRAY_ELEMENTS[0]) << 24 | (0xFF & ARRAY_ELEMENTS[1]) << 16
|
||||
| (0xFF & ARRAY_ELEMENTS[2]) << 8 | (0xFF & ARRAY_ELEMENTS[3]), value);
|
||||
testReadInt(0);
|
||||
testReadInt(1);
|
||||
testReadInt(-1);
|
||||
testReadInt(Integer.MIN_VALUE);
|
||||
testReadInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public void testSkipBack() {
|
||||
// When reading an unsigned integer
|
||||
long value = parsableByteArray.readUnsignedInt();
|
||||
private static void testReadInt(int testValue) {
|
||||
ParsableByteArray testArray = new ParsableByteArray(
|
||||
ByteBuffer.allocate(4).putInt(testValue).array());
|
||||
int readValue = testArray.readInt();
|
||||
|
||||
// Then skipping back and reading gives the same value.
|
||||
parsableByteArray.skip(-4);
|
||||
assertEquals(value, parsableByteArray.readUnsignedInt());
|
||||
// Assert that the value we read was the value we wrote.
|
||||
assertEquals(testValue, readValue);
|
||||
// And that the position advanced as expected.
|
||||
assertEquals(4, testArray.getPosition());
|
||||
|
||||
// And that skipping back and reading gives the same results.
|
||||
testArray.skipBytes(-4);
|
||||
readValue = testArray.readInt();
|
||||
assertEquals(testValue, readValue);
|
||||
assertEquals(4, testArray.getPosition());
|
||||
}
|
||||
|
||||
public void testReadUnsignedInt() {
|
||||
testReadUnsignedInt(0);
|
||||
testReadUnsignedInt(1);
|
||||
testReadUnsignedInt(Integer.MAX_VALUE);
|
||||
testReadUnsignedInt(Integer.MAX_VALUE + 1L);
|
||||
testReadUnsignedInt(0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
private static void testReadUnsignedInt(long testValue) {
|
||||
ParsableByteArray testArray = new ParsableByteArray(
|
||||
Arrays.copyOfRange(ByteBuffer.allocate(8).putLong(testValue).array(), 4, 8));
|
||||
long readValue = testArray.readUnsignedInt();
|
||||
|
||||
// Assert that the value we read was the value we wrote.
|
||||
assertEquals(testValue, readValue);
|
||||
// And that the position advanced as expected.
|
||||
assertEquals(4, testArray.getPosition());
|
||||
|
||||
// And that skipping back and reading gives the same results.
|
||||
testArray.skipBytes(-4);
|
||||
readValue = testArray.readUnsignedInt();
|
||||
assertEquals(testValue, readValue);
|
||||
assertEquals(4, testArray.getPosition());
|
||||
}
|
||||
|
||||
public void testReadUnsignedIntToInt() {
|
||||
testReadUnsignedIntToInt(0);
|
||||
testReadUnsignedIntToInt(1);
|
||||
testReadUnsignedIntToInt(Integer.MAX_VALUE);
|
||||
try {
|
||||
testReadUnsignedIntToInt(-1);
|
||||
fail();
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
}
|
||||
try {
|
||||
testReadUnsignedIntToInt(Integer.MIN_VALUE);
|
||||
fail();
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
|
||||
private static void testReadUnsignedIntToInt(int testValue) {
|
||||
ParsableByteArray testArray = new ParsableByteArray(
|
||||
ByteBuffer.allocate(4).putInt(testValue).array());
|
||||
int readValue = testArray.readUnsignedIntToInt();
|
||||
|
||||
// Assert that the value we read was the value we wrote.
|
||||
assertEquals(testValue, readValue);
|
||||
// And that the position advanced as expected.
|
||||
assertEquals(4, testArray.getPosition());
|
||||
|
||||
// And that skipping back and reading gives the same results.
|
||||
testArray.skipBytes(-4);
|
||||
readValue = testArray.readUnsignedIntToInt();
|
||||
assertEquals(testValue, readValue);
|
||||
assertEquals(4, testArray.getPosition());
|
||||
}
|
||||
|
||||
public void testReadUnsignedLongToLong() {
|
||||
testReadUnsignedLongToLong(0);
|
||||
testReadUnsignedLongToLong(1);
|
||||
testReadUnsignedLongToLong(Long.MAX_VALUE);
|
||||
try {
|
||||
testReadUnsignedLongToLong(-1);
|
||||
fail();
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
}
|
||||
try {
|
||||
testReadUnsignedLongToLong(Long.MIN_VALUE);
|
||||
fail();
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
|
||||
private static void testReadUnsignedLongToLong(long testValue) {
|
||||
ParsableByteArray testArray = new ParsableByteArray(
|
||||
ByteBuffer.allocate(8).putLong(testValue).array());
|
||||
long readValue = testArray.readUnsignedLongToLong();
|
||||
|
||||
// Assert that the value we read was the value we wrote.
|
||||
assertEquals(testValue, readValue);
|
||||
// And that the position advanced as expected.
|
||||
assertEquals(8, testArray.getPosition());
|
||||
|
||||
// And that skipping back and reading gives the same results.
|
||||
testArray.skipBytes(-8);
|
||||
readValue = testArray.readUnsignedLongToLong();
|
||||
assertEquals(testValue, readValue);
|
||||
assertEquals(8, testArray.getPosition());
|
||||
}
|
||||
|
||||
public void testReadLong() {
|
||||
testReadLong(0);
|
||||
testReadLong(1);
|
||||
testReadLong(-1);
|
||||
testReadLong(Long.MIN_VALUE);
|
||||
testReadLong(Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
private static void testReadLong(long testValue) {
|
||||
ParsableByteArray testArray = new ParsableByteArray(
|
||||
ByteBuffer.allocate(8).putLong(testValue).array());
|
||||
long readValue = testArray.readLong();
|
||||
|
||||
// Assert that the value we read was the value we wrote.
|
||||
assertEquals(testValue, readValue);
|
||||
// And that the position advanced as expected.
|
||||
assertEquals(8, testArray.getPosition());
|
||||
|
||||
// And that skipping back and reading gives the same results.
|
||||
testArray.skipBytes(-8);
|
||||
readValue = testArray.readLong();
|
||||
assertEquals(testValue, readValue);
|
||||
assertEquals(8, testArray.getPosition());
|
||||
}
|
||||
|
||||
public void testReadingMovesPosition() {
|
||||
ParsableByteArray parsableByteArray = getTestDataArray();
|
||||
|
||||
// Given an array at the start
|
||||
assertEquals(0, parsableByteArray.getPosition());
|
||||
|
||||
// When reading an integer, the position advances
|
||||
parsableByteArray.readUnsignedInt();
|
||||
assertEquals(4, parsableByteArray.getPosition());
|
||||
}
|
||||
|
||||
public void testOutOfBoundsThrows() {
|
||||
ParsableByteArray parsableByteArray = getTestDataArray();
|
||||
|
||||
// Given an array at the end
|
||||
parsableByteArray.readUnsignedLongToLong();
|
||||
assertEquals(ARRAY_ELEMENTS.length, parsableByteArray.getPosition());
|
||||
|
||||
assertEquals(TEST_DATA.length, parsableByteArray.getPosition());
|
||||
// Then reading more data throws.
|
||||
try {
|
||||
parsableByteArray.readUnsignedInt();
|
||||
|
|
@ -77,21 +205,23 @@ public class ParsableByteArrayTest extends TestCase {
|
|||
}
|
||||
|
||||
public void testModificationsAffectParsableArray() {
|
||||
ParsableByteArray parsableByteArray = getTestDataArray();
|
||||
|
||||
// When modifying the wrapped byte array
|
||||
byte[] data = parsableByteArray.data;
|
||||
long readValue = parsableByteArray.readUnsignedInt();
|
||||
data[0] = (byte) (ARRAY_ELEMENTS[0] + 1);
|
||||
data[0] = (byte) (TEST_DATA[0] + 1);
|
||||
parsableByteArray.setPosition(0);
|
||||
|
||||
// Then the parsed value changes.
|
||||
assertFalse(parsableByteArray.readUnsignedInt() == readValue);
|
||||
}
|
||||
|
||||
public void testReadingUnsignedLongWithMsbSetThrows() {
|
||||
ParsableByteArray parsableByteArray = getTestDataArray();
|
||||
|
||||
// Given an array with the most-significant bit set on the top byte
|
||||
byte[] data = parsableByteArray.data;
|
||||
data[0] = (byte) 0x80;
|
||||
|
||||
// Then reading an unsigned long throws.
|
||||
try {
|
||||
parsableByteArray.readUnsignedLongToLong();
|
||||
|
|
@ -102,21 +232,23 @@ public class ParsableByteArrayTest extends TestCase {
|
|||
}
|
||||
|
||||
public void testReadUnsignedFixedPoint1616() {
|
||||
ParsableByteArray parsableByteArray = getTestDataArray();
|
||||
|
||||
// When reading the integer part of a 16.16 fixed point value
|
||||
int value = parsableByteArray.readUnsignedFixedPoint1616();
|
||||
|
||||
// Then the read value is equal to the array elements interpreted as a short.
|
||||
assertEquals((0xFF & ARRAY_ELEMENTS[0]) << 8 | (ARRAY_ELEMENTS[1] & 0xFF), value);
|
||||
assertEquals((0xFF & TEST_DATA[0]) << 8 | (TEST_DATA[1] & 0xFF), value);
|
||||
assertEquals(4, parsableByteArray.getPosition());
|
||||
}
|
||||
|
||||
public void testReadingBytesReturnsCopy() {
|
||||
ParsableByteArray parsableByteArray = getTestDataArray();
|
||||
|
||||
// When reading all the bytes back
|
||||
int length = parsableByteArray.limit();
|
||||
assertEquals(ARRAY_ELEMENTS.length, length);
|
||||
assertEquals(TEST_DATA.length, length);
|
||||
byte[] copy = new byte[length];
|
||||
parsableByteArray.readBytes(copy, 0, length);
|
||||
|
||||
// Then the array elements are the same.
|
||||
assertTrue(Arrays.equals(parsableByteArray.data, copy));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue