use of com.google.android.exoplayer2.util.ParsableByteArray in project ExoPlayer by google.
the class WavHeaderReader method peek.
/**
* Peeks and returns a {@code WavHeader}.
*
* @param input Input stream to peek the WAV header from.
* @throws ParserException If the input file is an incorrect RIFF WAV.
* @throws IOException If peeking from the input fails.
* @throws InterruptedException If interrupted while peeking from input.
* @return A new {@code WavHeader} peeked from {@code input}, or null if the input is not a
* supported WAV format.
*/
public static WavHeader peek(ExtractorInput input) throws IOException, InterruptedException {
Assertions.checkNotNull(input);
// Allocate a scratch buffer large enough to store the format chunk.
ParsableByteArray scratch = new ParsableByteArray(16);
// Attempt to read the RIFF chunk.
ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch);
if (chunkHeader.id != Util.getIntegerCodeForString("RIFF")) {
return null;
}
input.peekFully(scratch.data, 0, 4);
scratch.setPosition(0);
int riffFormat = scratch.readInt();
if (riffFormat != Util.getIntegerCodeForString("WAVE")) {
Log.e(TAG, "Unsupported RIFF format: " + riffFormat);
return null;
}
// Skip chunks until we find the format chunk.
chunkHeader = ChunkHeader.peek(input, scratch);
while (chunkHeader.id != Util.getIntegerCodeForString("fmt ")) {
input.advancePeekPosition((int) chunkHeader.size);
chunkHeader = ChunkHeader.peek(input, scratch);
}
Assertions.checkState(chunkHeader.size >= 16);
input.peekFully(scratch.data, 0, 16);
scratch.setPosition(0);
int type = scratch.readLittleEndianUnsignedShort();
int numChannels = scratch.readLittleEndianUnsignedShort();
int sampleRateHz = scratch.readLittleEndianUnsignedIntToInt();
int averageBytesPerSecond = scratch.readLittleEndianUnsignedIntToInt();
int blockAlignment = scratch.readLittleEndianUnsignedShort();
int bitsPerSample = scratch.readLittleEndianUnsignedShort();
int expectedBlockAlignment = numChannels * bitsPerSample / 8;
if (blockAlignment != expectedBlockAlignment) {
throw new ParserException("Expected block alignment: " + expectedBlockAlignment + "; got: " + blockAlignment);
}
@C.PcmEncoding int encoding = Util.getPcmEncoding(bitsPerSample);
if (encoding == C.ENCODING_INVALID) {
Log.e(TAG, "Unsupported WAV bit depth: " + bitsPerSample);
return null;
}
if (type != TYPE_PCM && type != TYPE_WAVE_FORMAT_EXTENSIBLE) {
Log.e(TAG, "Unsupported WAV format type: " + type);
return null;
}
// If present, skip extensionSize, validBitsPerSample, channelMask, subFormatGuid, ...
input.advancePeekPosition((int) chunkHeader.size - 16);
return new WavHeader(numChannels, sampleRateHz, averageBytesPerSecond, blockAlignment, bitsPerSample, encoding);
}
use of com.google.android.exoplayer2.util.ParsableByteArray in project ExoPlayer by google.
the class MetadataUtil method parseUint8Attribute.
private static Id3Frame parseUint8Attribute(int type, String id, ParsableByteArray data, boolean isTextInformationFrame, boolean isBoolean) {
int value = parseUint8AttributeValue(data);
if (isBoolean) {
value = Math.min(1, value);
}
if (value >= 0) {
return isTextInformationFrame ? new TextInformationFrame(id, null, Integer.toString(value)) : new CommentFrame(LANGUAGE_UNDEFINED, id, Integer.toString(value));
}
Log.w(TAG, "Failed to parse uint8 attribute: " + Atom.getAtomTypeString(type));
return null;
}
use of com.google.android.exoplayer2.util.ParsableByteArray in project ExoPlayer by google.
the class Mp4Extractor method readAtomHeader.
private boolean readAtomHeader(ExtractorInput input) throws IOException, InterruptedException {
if (atomHeaderBytesRead == 0) {
// Read the standard length atom header.
if (!input.readFully(atomHeader.data, 0, Atom.HEADER_SIZE, true)) {
return false;
}
atomHeaderBytesRead = Atom.HEADER_SIZE;
atomHeader.setPosition(0);
atomSize = atomHeader.readUnsignedInt();
atomType = atomHeader.readInt();
}
if (atomSize == Atom.LONG_SIZE_PREFIX) {
// Read the extended atom size.
int headerBytesRemaining = Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE;
input.readFully(atomHeader.data, Atom.HEADER_SIZE, headerBytesRemaining);
atomHeaderBytesRead += headerBytesRemaining;
atomSize = atomHeader.readUnsignedLongToLong();
}
if (shouldParseContainerAtom(atomType)) {
long endPosition = input.getPosition() + atomSize - atomHeaderBytesRead;
containerAtoms.add(new ContainerAtom(atomType, endPosition));
if (atomSize == atomHeaderBytesRead) {
processAtomEnded(endPosition);
} else {
// Start reading the first child atom.
enterReadingAtomHeaderState();
}
} else if (shouldParseLeafAtom(atomType)) {
// We don't support parsing of leaf atoms that define extended atom sizes, or that have
// lengths greater than Integer.MAX_VALUE.
Assertions.checkState(atomHeaderBytesRead == Atom.HEADER_SIZE);
Assertions.checkState(atomSize <= Integer.MAX_VALUE);
atomData = new ParsableByteArray((int) atomSize);
System.arraycopy(atomHeader.data, 0, atomData.data, 0, Atom.HEADER_SIZE);
parserState = STATE_READING_ATOM_PAYLOAD;
} else {
atomData = null;
parserState = STATE_READING_ATOM_PAYLOAD;
}
return true;
}
use of com.google.android.exoplayer2.util.ParsableByteArray in project ExoPlayer by google.
the class Sniffer method sniffInternal.
private static boolean sniffInternal(ExtractorInput input, boolean fragmented) throws IOException, InterruptedException {
long inputLength = input.getLength();
int bytesToSearch = (int) (inputLength == C.LENGTH_UNSET || inputLength > SEARCH_LENGTH ? SEARCH_LENGTH : inputLength);
ParsableByteArray buffer = new ParsableByteArray(64);
int bytesSearched = 0;
boolean foundGoodFileType = false;
boolean isFragmented = false;
while (bytesSearched < bytesToSearch) {
// Read an atom header.
int headerSize = Atom.HEADER_SIZE;
buffer.reset(headerSize);
input.peekFully(buffer.data, 0, headerSize);
long atomSize = buffer.readUnsignedInt();
int atomType = buffer.readInt();
if (atomSize == Atom.LONG_SIZE_PREFIX) {
headerSize = Atom.LONG_HEADER_SIZE;
input.peekFully(buffer.data, Atom.HEADER_SIZE, Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE);
buffer.setLimit(Atom.LONG_HEADER_SIZE);
atomSize = buffer.readUnsignedLongToLong();
}
if (atomSize < headerSize) {
// The file is invalid because the atom size is too small for its header.
return false;
}
bytesSearched += headerSize;
if (atomType == Atom.TYPE_moov) {
// Check for an mvex atom inside the moov atom to identify whether the file is fragmented.
continue;
}
if (atomType == Atom.TYPE_moof || atomType == Atom.TYPE_mvex) {
// The movie is fragmented. Stop searching as we must have read any ftyp atom already.
isFragmented = true;
break;
}
if (bytesSearched + atomSize - headerSize >= bytesToSearch) {
// Stop searching as peeking this atom would exceed the search limit.
break;
}
int atomDataSize = (int) (atomSize - headerSize);
bytesSearched += atomDataSize;
if (atomType == Atom.TYPE_ftyp) {
// Parse the atom and check the file type/brand is compatible with the extractors.
if (atomDataSize < 8) {
return false;
}
buffer.reset(atomDataSize);
input.peekFully(buffer.data, 0, atomDataSize);
int brandsCount = atomDataSize / 4;
for (int i = 0; i < brandsCount; i++) {
if (i == 1) {
// This index refers to the minorVersion, not a brand, so skip it.
buffer.skipBytes(4);
} else if (isCompatibleBrand(buffer.readInt())) {
foundGoodFileType = true;
break;
}
}
if (!foundGoodFileType) {
// The types were not compatible and there is only one ftyp atom, so reject the file.
return false;
}
} else if (atomDataSize != 0) {
// Skip the atom.
input.advancePeekPosition(atomDataSize);
}
}
return foundGoodFileType && fragmented == isFragmented;
}
use of com.google.android.exoplayer2.util.ParsableByteArray in project ExoPlayer by google.
the class TrackFragment method initEncryptionData.
/**
* Configures the fragment to be one that defines encryption data of the specified length.
* <p>
* {@link #definesEncryptionData} is set to true, {@link #sampleEncryptionDataLength} is set to
* the specified length, and {@link #sampleEncryptionData} is resized if necessary such that it
* is at least this length.
*
* @param length The length in bytes of the encryption data.
*/
public void initEncryptionData(int length) {
if (sampleEncryptionData == null || sampleEncryptionData.limit() < length) {
sampleEncryptionData = new ParsableByteArray(length);
}
sampleEncryptionDataLength = length;
definesEncryptionData = true;
sampleEncryptionDataNeedsFill = true;
}
Aggregations