use of com.google.android.exoplayer2.extractor.ExtractorInput in project ExoPlayer by google.
the class JpegExtractor method readSegment.
private void readSegment(ExtractorInput input) throws IOException {
if (marker == MARKER_APP1) {
ParsableByteArray payload = new ParsableByteArray(segmentLength);
input.readFully(payload.getData(), /* offset= */
0, /* length= */
segmentLength);
if (motionPhotoMetadata == null && HEADER_XMP_APP1.equals(payload.readNullTerminatedString())) {
@Nullable String xmpString = payload.readNullTerminatedString();
if (xmpString != null) {
motionPhotoMetadata = getMotionPhotoMetadata(xmpString, input.getLength());
if (motionPhotoMetadata != null) {
mp4StartPosition = motionPhotoMetadata.videoStartPosition;
}
}
}
} else {
input.skipFully(segmentLength);
}
state = STATE_READING_MARKER;
}
use of com.google.android.exoplayer2.extractor.ExtractorInput in project ExoPlayer by google.
the class Sniffer method sniffInternal.
private static boolean sniffInternal(ExtractorInput input, boolean fragmented, boolean acceptHeic) throws IOException {
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);
boolean success = input.peekFully(buffer.getData(), 0, headerSize, /* allowEndOfInput= */
true);
if (!success) {
// We've reached the end of the file.
break;
}
long atomSize = buffer.readUnsignedInt();
int atomType = buffer.readInt();
if (atomSize == Atom.DEFINES_LARGE_SIZE) {
// Read the large atom size.
headerSize = Atom.LONG_HEADER_SIZE;
input.peekFully(buffer.getData(), Atom.HEADER_SIZE, Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE);
buffer.setLimit(Atom.LONG_HEADER_SIZE);
atomSize = buffer.readLong();
} else if (atomSize == Atom.EXTENDS_TO_END_SIZE) {
// The atom extends to the end of the file.
long fileEndPosition = input.getLength();
if (fileEndPosition != C.LENGTH_UNSET) {
atomSize = fileEndPosition - input.getPeekPosition() + headerSize;
}
}
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) {
// We have seen the moov atom. We increase the search size to make sure we don't miss an
// mvex atom because the moov's size exceeds the search length.
bytesToSearch += (int) atomSize;
if (inputLength != C.LENGTH_UNSET && bytesToSearch > inputLength) {
// Make sure we don't exceed the file size.
bytesToSearch = (int) inputLength;
}
// 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.getData(), 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(), acceptHeic)) {
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.extractor.ExtractorInput in project ExoPlayer by google.
the class DefaultOggSeeker method getNextSeekPosition.
/**
* Performs a single step of a seeking binary search, returning the byte position from which data
* should be provided for the next step, or {@link C#POSITION_UNSET} if the search has converged.
* If the search has converged then {@link #skipToPageOfTargetGranule(ExtractorInput)} should be
* called to skip to the target page.
*
* @param input The {@link ExtractorInput} to read from.
* @return The byte position from which data should be provided for the next step, or {@link
* C#POSITION_UNSET} if the search has converged.
* @throws IOException If reading from the input fails.
*/
private long getNextSeekPosition(ExtractorInput input) throws IOException {
if (start == end) {
return C.POSITION_UNSET;
}
long currentPosition = input.getPosition();
if (!pageHeader.skipToNextPage(input, end)) {
if (start == currentPosition) {
throw new IOException("No ogg page can be found.");
}
return start;
}
pageHeader.populate(input, /* quiet= */
false);
input.resetPeekPosition();
long granuleDistance = targetGranule - pageHeader.granulePosition;
int pageSize = pageHeader.headerSize + pageHeader.bodySize;
if (0 <= granuleDistance && granuleDistance < MATCH_RANGE) {
return C.POSITION_UNSET;
}
if (granuleDistance < 0) {
end = currentPosition;
endGranule = pageHeader.granulePosition;
} else {
start = input.getPosition() + pageSize;
startGranule = pageHeader.granulePosition;
}
if (end - start < MATCH_BYTE_RANGE) {
end = start;
return start;
}
long offset = pageSize * (granuleDistance <= 0 ? 2L : 1L);
long nextPosition = input.getPosition() - offset + (granuleDistance * (end - start) / (endGranule - startGranule));
return Util.constrainValue(nextPosition, start, end - 1);
}
use of com.google.android.exoplayer2.extractor.ExtractorInput in project ExoPlayer by google.
the class OggExtractor method read.
@Override
public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException {
// Check that init has been called.
checkStateNotNull(output);
if (streamReader == null) {
if (!sniffInternal(input)) {
throw ParserException.createForMalformedContainer("Failed to determine bitstream type", /* cause= */
null);
}
input.resetPeekPosition();
}
if (!streamReaderInitialized) {
TrackOutput trackOutput = output.track(0, C.TRACK_TYPE_AUDIO);
output.endTracks();
streamReader.init(output, trackOutput);
streamReaderInitialized = true;
}
return streamReader.read(input, seekPosition);
}
use of com.google.android.exoplayer2.extractor.ExtractorInput in project ExoPlayer by google.
the class FlacFrameReader method checkFrameHeaderFromPeek.
/**
* Checks whether the given FLAC frame header is valid and, if so, writes the frame first sample
* number in {@code sampleNumberHolder}.
*
* <p>The {@code input} peek position is left unchanged.
*
* @param input The input to get the data from, whose peek position must correspond to the frame
* header.
* @param flacStreamMetadata The stream metadata.
* @param frameStartMarker The frame start marker of the stream.
* @param sampleNumberHolder The holder used to contain the sample number.
* @return Whether the frame header is valid.
*/
public static boolean checkFrameHeaderFromPeek(ExtractorInput input, FlacStreamMetadata flacStreamMetadata, int frameStartMarker, SampleNumberHolder sampleNumberHolder) throws IOException {
long originalPeekPosition = input.getPeekPosition();
byte[] frameStartBytes = new byte[2];
input.peekFully(frameStartBytes, 0, 2);
int frameStart = (frameStartBytes[0] & 0xFF) << 8 | (frameStartBytes[1] & 0xFF);
if (frameStart != frameStartMarker) {
input.resetPeekPosition();
input.advancePeekPosition((int) (originalPeekPosition - input.getPosition()));
return false;
}
ParsableByteArray scratch = new ParsableByteArray(FlacConstants.MAX_FRAME_HEADER_SIZE);
System.arraycopy(frameStartBytes, /* srcPos= */
0, scratch.getData(), /* destPos= */
0, /* length= */
2);
int totalBytesPeeked = ExtractorUtil.peekToLength(input, scratch.getData(), 2, FlacConstants.MAX_FRAME_HEADER_SIZE - 2);
scratch.setLimit(totalBytesPeeked);
input.resetPeekPosition();
input.advancePeekPosition((int) (originalPeekPosition - input.getPosition()));
return checkAndReadFrameHeader(scratch, flacStreamMetadata, frameStartMarker, sampleNumberHolder);
}
Aggregations