Search in sources :

Example 56 with ExtractorInput

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;
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) Nullable(androidx.annotation.Nullable)

Example 57 with ExtractorInput

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;
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray)

Example 58 with ExtractorInput

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);
}
Also used : IOException(java.io.IOException) SeekPoint(com.google.android.exoplayer2.extractor.SeekPoint)

Example 59 with ExtractorInput

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);
}
Also used : TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput)

Example 60 with ExtractorInput

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);
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray)

Aggregations

FakeExtractorInput (com.google.android.exoplayer2.testutil.FakeExtractorInput)85 Test (org.junit.Test)71 ExtractorInput (com.google.android.exoplayer2.extractor.ExtractorInput)53 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)39 FlacStreamMetadataHolder (com.google.android.exoplayer2.extractor.FlacMetadataReader.FlacStreamMetadataHolder)20 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)17 DefaultExtractorInput (com.google.android.exoplayer2.extractor.DefaultExtractorInput)16 Nullable (androidx.annotation.Nullable)15 Metadata (com.google.android.exoplayer2.metadata.Metadata)13 SampleNumberHolder (com.google.android.exoplayer2.extractor.FlacFrameReader.SampleNumberHolder)9 FakeDataSource (com.google.android.exoplayer2.testutil.FakeDataSource)9 EOFException (java.io.EOFException)8 SeekPoint (com.google.android.exoplayer2.extractor.SeekPoint)7 RequiresNonNull (org.checkerframework.checker.nullness.qual.RequiresNonNull)7 ParserException (com.google.android.exoplayer2.ParserException)5 SeekMap (com.google.android.exoplayer2.extractor.SeekMap)5 TrackOutput (com.google.android.exoplayer2.extractor.TrackOutput)5 IOException (java.io.IOException)5 PositionHolder (com.google.android.exoplayer2.extractor.PositionHolder)3 Id3Decoder (com.google.android.exoplayer2.metadata.id3.Id3Decoder)3