com.google.android.exoplayer.util.ParsableByteArray

Here are the examples of the java api class com.google.android.exoplayer.util.ParsableByteArray taken from open source projects.

1. AtomParsers#parseEdts()

Project: ExoPlayer
Source File: AtomParsers.java
View license
/**
   * Parses the edts atom (defined in 14496-12 subsection 8.6.5).
   *
   * @param edtsAtom edts (edit box) atom to parse.
   * @return Pair of edit list durations and edit list media times, or a pair of nulls if they are
   *     not present.
   */
private static Pair<long[], long[]> parseEdts(Atom.ContainerAtom edtsAtom) {
    Atom.LeafAtom elst;
    if (edtsAtom == null || (elst = edtsAtom.getLeafAtomOfType(Atom.TYPE_elst)) == null) {
        return Pair.create(null, null);
    }
    ParsableByteArray elstData = elst.data;
    elstData.setPosition(Atom.HEADER_SIZE);
    int fullAtom = elstData.readInt();
    int version = Atom.parseFullAtomVersion(fullAtom);
    int entryCount = elstData.readUnsignedIntToInt();
    long[] editListDurations = new long[entryCount];
    long[] editListMediaTimes = new long[entryCount];
    for (int i = 0; i < entryCount; i++) {
        editListDurations[i] = version == 1 ? elstData.readUnsignedLongToLong() : elstData.readUnsignedInt();
        editListMediaTimes[i] = version == 1 ? elstData.readLong() : elstData.readInt();
        int mediaRateInteger = elstData.readShort();
        if (mediaRateInteger != 1) {
            // The extractor does not handle dwell edits (mediaRateInteger == 0).
            throw new IllegalArgumentException("Unsupported media rate.");
        }
        elstData.skipBytes(2);
    }
    return Pair.create(editListDurations, editListMediaTimes);
}

2. AtomParsers#parseUdta()

Project: ExoPlayer
Source File: AtomParsers.java
View license
/**
   * Parses a udta atom.
   *
   * @param udtaAtom The udta (user data) atom to parse.
   * @param isQuickTime True for QuickTime media. False otherwise.
   * @return Gapless playback information stored in the user data, or {@code null} if not present.
   */
public static GaplessInfo parseUdta(Atom.LeafAtom udtaAtom, boolean isQuickTime) {
    if (isQuickTime) {
        // parse one.
        return null;
    }
    ParsableByteArray udtaData = udtaAtom.data;
    udtaData.setPosition(Atom.HEADER_SIZE);
    while (udtaData.bytesLeft() >= Atom.HEADER_SIZE) {
        int atomSize = udtaData.readInt();
        int atomType = udtaData.readInt();
        if (atomType == Atom.TYPE_meta) {
            udtaData.setPosition(udtaData.getPosition() - Atom.HEADER_SIZE);
            udtaData.setLimit(udtaData.getPosition() + atomSize);
            return parseMetaAtom(udtaData);
        } else {
            udtaData.skipBytes(atomSize - Atom.HEADER_SIZE);
        }
    }
    return null;
}

3. OggUtilTest#testPopulatePageHeader()

Project: ExoPlayer
Source File: OggUtilTest.java
View license
public void testPopulatePageHeader() throws IOException, InterruptedException {
    FakeExtractorInput input = TestData.createInput(TestUtil.joinByteArrays(TestData.buildOggHeader(0x01, 123456, 4, 2), TestUtil.createByteArray(2, 2)), true);
    OggUtil.PageHeader header = new OggUtil.PageHeader();
    ParsableByteArray byteArray = new ParsableByteArray(27 + 2);
    populatePageHeader(input, header, byteArray, false);
    assertEquals(0x01, header.type);
    assertEquals(27 + 2, header.headerSize);
    assertEquals(4, header.bodySize);
    assertEquals(2, header.pageSegmentCount);
    assertEquals(123456, header.granulePosition);
    assertEquals(4, header.pageSequenceNumber);
    assertEquals(0x1000, header.streamSerialNumber);
    assertEquals(0x100000, header.pageChecksum);
    assertEquals(0, header.revision);
}

4. OggUtilTest#testPopulatePageHeaderQuiteOnExceptionNotOgg()

Project: ExoPlayer
Source File: OggUtilTest.java
View license
public void testPopulatePageHeaderQuiteOnExceptionNotOgg() throws IOException, InterruptedException {
    byte[] headerBytes = TestUtil.joinByteArrays(TestData.buildOggHeader(0x01, 123456, 4, 2), TestUtil.createByteArray(2, 2));
    // change from 'O' to 'o'
    headerBytes[0] = 'o';
    FakeExtractorInput input = TestData.createInput(headerBytes, false);
    OggUtil.PageHeader header = new OggUtil.PageHeader();
    ParsableByteArray byteArray = new ParsableByteArray(27 + 2);
    assertFalse(populatePageHeader(input, header, byteArray, true));
}

5. OggUtilTest#testPopulatePageHeaderQuiteOnExceptionWrongRevision()

Project: ExoPlayer
Source File: OggUtilTest.java
View license
public void testPopulatePageHeaderQuiteOnExceptionWrongRevision() throws IOException, InterruptedException {
    byte[] headerBytes = TestUtil.joinByteArrays(TestData.buildOggHeader(0x01, 123456, 4, 2), TestUtil.createByteArray(2, 2));
    // change revision from 0 to 1
    headerBytes[4] = 0x01;
    FakeExtractorInput input = TestData.createInput(headerBytes, false);
    OggUtil.PageHeader header = new OggUtil.PageHeader();
    ParsableByteArray byteArray = new ParsableByteArray(27 + 2);
    assertFalse(populatePageHeader(input, header, byteArray, true));
}

6. VorbisUtilTest#testReadIdHeader()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testReadIdHeader() throws Exception {
    byte[] data = TestData.getIdentificationHeaderData();
    ParsableByteArray headerData = new ParsableByteArray(data, data.length);
    VorbisUtil.VorbisIdHeader vorbisIdHeader = VorbisUtil.readVorbisIdentificationHeader(headerData);
    assertEquals(22050, vorbisIdHeader.sampleRate);
    assertEquals(0, vorbisIdHeader.version);
    assertTrue(vorbisIdHeader.framingFlag);
    assertEquals(2, vorbisIdHeader.channels);
    assertEquals(512, vorbisIdHeader.blockSize0);
    assertEquals(1024, vorbisIdHeader.blockSize1);
    assertEquals(-1, vorbisIdHeader.bitrateMax);
    assertEquals(-1, vorbisIdHeader.bitrateMin);
    assertEquals(66666, vorbisIdHeader.bitrateNominal);
    assertEquals(66666, vorbisIdHeader.getApproximateBitrate());
}

7. VorbisUtilTest#testReadVorbisModes()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testReadVorbisModes() throws ParserException {
    byte[] data = TestData.getSetupHeaderData();
    ParsableByteArray headerData = new ParsableByteArray(data, data.length);
    VorbisUtil.Mode[] modes = VorbisUtil.readVorbisModes(headerData, 2);
    assertEquals(2, modes.length);
    assertEquals(false, modes[0].blockFlag);
    assertEquals(0, modes[0].mapping);
    assertEquals(0, modes[0].transformType);
    assertEquals(0, modes[0].windowType);
    assertEquals(true, modes[1].blockFlag);
    assertEquals(1, modes[1].mapping);
    assertEquals(0, modes[1].transformType);
    assertEquals(0, modes[1].windowType);
}

8. AtomParsers#parseMetaAtom()

Project: ExoPlayer
Source File: AtomParsers.java
View license
private static GaplessInfo parseMetaAtom(ParsableByteArray data) {
    data.skipBytes(Atom.FULL_HEADER_SIZE);
    ParsableByteArray ilst = new ParsableByteArray();
    while (data.bytesLeft() >= Atom.HEADER_SIZE) {
        int payloadSize = data.readInt() - Atom.HEADER_SIZE;
        int atomType = data.readInt();
        if (atomType == Atom.TYPE_ilst) {
            ilst.reset(data.data, data.getPosition() + payloadSize);
            ilst.setPosition(data.getPosition());
            GaplessInfo gaplessInfo = parseIlst(ilst);
            if (gaplessInfo != null) {
                return gaplessInfo;
            }
        }
        data.skipBytes(payloadSize);
    }
    return null;
}

9. WavHeaderReader#peek()

Project: ExoPlayer
Source File: WavHeaderReader.java
View license
/**
   * Peeks and returns a {@code WavHeader}.
   *
   * @param input Input stream to peek the WAV header from.
   * @throws IOException If peeking from the input fails.
   * @throws InterruptedException If interrupted while peeking from input.
   * @throws ParserException If the input file is an incorrect RIFF WAV.
   * @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, ParserException {
    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);
    }
    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);
}

10. PsshAtomUtil#parsePsshAtom()

Project: ExoPlayer
Source File: PsshAtomUtil.java
View license
/**
   * Parses the UUID and scheme specific data from a PSSH atom. Version 0 and 1 PSSH atoms are
   * supported.
   *
   * @param atom The atom to parse.
   * @return A pair consisting of the parsed UUID and scheme specific data. Null if the input is
   *     not a valid PSSH atom, or if the PSSH atom has an unsupported version.
   */
private static Pair<UUID, byte[]> parsePsshAtom(byte[] atom) {
    ParsableByteArray atomData = new ParsableByteArray(atom);
    if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 + /* UUID */
    4) /* DataSize */
    {
        // Data too short.
        return null;
    }
    atomData.setPosition(0);
    int atomSize = atomData.readInt();
    if (atomSize != atomData.bytesLeft() + 4) {
        // Not an atom, or incorrect atom size.
        return null;
    }
    int atomType = atomData.readInt();
    if (atomType != Atom.TYPE_pssh) {
        // Not an atom, or incorrect atom type.
        return null;
    }
    int atomVersion = Atom.parseFullAtomVersion(atomData.readInt());
    if (atomVersion > 1) {
        Log.w(TAG, "Unsupported pssh version: " + atomVersion);
        return null;
    }
    UUID uuid = new UUID(atomData.readLong(), atomData.readLong());
    if (atomVersion == 1) {
        int keyIdCount = atomData.readUnsignedIntToInt();
        atomData.skipBytes(16 * keyIdCount);
    }
    int dataSize = atomData.readUnsignedIntToInt();
    if (dataSize != atomData.bytesLeft()) {
        // Incorrect dataSize.
        return null;
    }
    byte[] data = new byte[dataSize];
    atomData.readBytes(data, 0, dataSize);
    return Pair.create(uuid, data);
}

11. SubripParser#parse()

Project: ExoPlayer
Source File: SubripParser.java
View license
@Override
public SubripSubtitle parse(byte[] bytes, int offset, int length) {
    ArrayList<Cue> cues = new ArrayList<>();
    LongArray cueTimesUs = new LongArray();
    ParsableByteArray subripData = new ParsableByteArray(bytes, offset + length);
    subripData.setPosition(offset);
    boolean haveEndTimecode;
    String currentLine;
    while ((currentLine = subripData.readLine()) != null) {
        if (currentLine.length() == 0) {
            // Skip blank lines.
            continue;
        }
        // Parse the index line as a sanity check.
        try {
            Integer.parseInt(currentLine);
        } catch (NumberFormatException e) {
            Log.w(TAG, "Skipping invalid index: " + currentLine);
            continue;
        }
        // Read and parse the timing line.
        haveEndTimecode = false;
        currentLine = subripData.readLine();
        Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine);
        if (matcher.find()) {
            cueTimesUs.add(parseTimecode(matcher.group(1)));
            String endTimecode = matcher.group(2);
            if (!TextUtils.isEmpty(endTimecode)) {
                haveEndTimecode = true;
                cueTimesUs.add(parseTimecode(matcher.group(2)));
            }
        } else {
            Log.w(TAG, "Skipping invalid timing: " + currentLine);
            continue;
        }
        // Read and parse the text.
        textBuilder.setLength(0);
        while (!TextUtils.isEmpty(currentLine = subripData.readLine())) {
            if (textBuilder.length() > 0) {
                textBuilder.append("<br>");
            }
            textBuilder.append(currentLine.trim());
        }
        Spanned text = Html.fromHtml(textBuilder.toString());
        cues.add(new Cue(text));
        if (haveEndTimecode) {
            cues.add(null);
        }
    }
    Cue[] cuesArray = new Cue[cues.size()];
    cues.toArray(cuesArray);
    long[] cueTimesUsArray = cueTimesUs.toArray();
    return new SubripSubtitle(cuesArray, cueTimesUsArray);
}

12. FragmentedMp4Extractor#appendSampleEncryptionData()

View license
/**
   * Appends the corresponding encryption data to the {@link TrackOutput} contained in the given
   * {@link TrackBundle}.
   *
   * @param trackBundle The {@link TrackBundle} that contains the {@link Track} for which the
   *     Sample encryption data must be output.
   * @return The number of written bytes.
   */
private int appendSampleEncryptionData(TrackBundle trackBundle) {
    TrackFragment trackFragment = trackBundle.fragment;
    ParsableByteArray sampleEncryptionData = trackFragment.sampleEncryptionData;
    int sampleDescriptionIndex = trackFragment.header.sampleDescriptionIndex;
    TrackEncryptionBox encryptionBox = trackFragment.trackEncryptionBox != null ? trackFragment.trackEncryptionBox : trackBundle.track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex];
    int vectorSize = encryptionBox.initializationVectorSize;
    boolean subsampleEncryption = trackFragment.sampleHasSubsampleEncryptionTable[trackBundle.currentSampleIndex];
    // Write the signal byte, containing the vector size and the subsample encryption flag.
    encryptionSignalByte.data[0] = (byte) (vectorSize | (subsampleEncryption ? 0x80 : 0));
    encryptionSignalByte.setPosition(0);
    TrackOutput output = trackBundle.output;
    output.sampleData(encryptionSignalByte, 1);
    // Write the vector.
    output.sampleData(sampleEncryptionData, vectorSize);
    // If we don't have subsample encryption data, we're done.
    if (!subsampleEncryption) {
        return 1 + vectorSize;
    }
    // Write the subsample encryption data.
    int subsampleCount = sampleEncryptionData.readUnsignedShort();
    sampleEncryptionData.skipBytes(-2);
    int subsampleDataLength = 2 + 6 * subsampleCount;
    output.sampleData(sampleEncryptionData, subsampleDataLength);
    return 1 + vectorSize + subsampleDataLength;
}

13. Mp3Extractor#setupSeeker()

Project: ExoPlayer
Source File: Mp3Extractor.java
View license
/**
   * Sets {@link #seeker} to seek using metadata read from {@code input}, which should provide data
   * from the start of the first frame in the stream. On returning, the input's position will be set
   * to the start of the first frame of audio.
   *
   * @param input The {@link ExtractorInput} from which to read.
   * @throws IOException Thrown if there was an error reading from the stream. Not expected if the
   *     next two frames were already peeked during synchronization.
   * @throws InterruptedException Thrown if reading from the stream was interrupted. Not expected if
   *     the next two frames were already peeked during synchronization.
   */
private void setupSeeker(ExtractorInput input) throws IOException, InterruptedException {
    // Read the first frame which may contain a Xing or VBRI header with seeking metadata.
    ParsableByteArray frame = new ParsableByteArray(synchronizedHeader.frameSize);
    input.peekFully(frame.data, 0, synchronizedHeader.frameSize);
    long position = input.getPosition();
    long length = input.getLength();
    // Check if there is a Xing header.
    int xingBase = (synchronizedHeader.version & 1) != 0 ? // MPEG 1
    (synchronizedHeader.channels != 1 ? 36 : 21) : // MPEG 2 or 2.5
    (synchronizedHeader.channels != 1 ? 21 : 13);
    frame.setPosition(xingBase);
    int headerData = frame.readInt();
    if (headerData == XING_HEADER || headerData == INFO_HEADER) {
        seeker = XingSeeker.create(synchronizedHeader, frame, position, length);
        if (seeker != null && gaplessInfo == null) {
            // If there is a Xing header, read gapless playback metadata at a fixed offset.
            input.resetPeekPosition();
            input.advancePeekPosition(xingBase + 141);
            input.peekFully(scratch.data, 0, 3);
            scratch.setPosition(0);
            gaplessInfo = GaplessInfo.createFromXingHeaderValue(scratch.readUnsignedInt24());
        }
        input.skipFully(synchronizedHeader.frameSize);
    } else {
        // Check if there is a VBRI header.
        // MPEG audio header (4 bytes) + 32 bytes.
        frame.setPosition(36);
        headerData = frame.readInt();
        if (headerData == VBRI_HEADER) {
            seeker = VbriSeeker.create(synchronizedHeader, frame, position, length);
            input.skipFully(synchronizedHeader.frameSize);
        }
    }
    if (seeker == null) {
        // Repopulate the synchronized header in case we had to skip an invalid seeking header, which
        // would give an invalid CBR bitrate.
        input.resetPeekPosition();
        input.peekFully(scratch.data, 0, 4);
        scratch.setPosition(0);
        MpegAudioHeader.populateHeader(scratch.readInt(), synchronizedHeader);
        seeker = new ConstantBitrateSeeker(input.getPosition(), synchronizedHeader.bitrate, length);
    }
}

14. VorbisReaderTest#testAppendNumberOfSamples()

Project: ExoPlayer
Source File: VorbisReaderTest.java
View license
public void testAppendNumberOfSamples() throws Exception {
    ParsableByteArray buffer = new ParsableByteArray(4);
    buffer.setLimit(0);
    VorbisReader.appendNumberOfSamples(buffer, 0x01234567);
    assertEquals(4, buffer.limit());
    assertEquals(0x67, buffer.data[0]);
    assertEquals(0x45, buffer.data[1]);
    assertEquals(0x23, buffer.data[2]);
    assertEquals(0x01, buffer.data[3]);
}

15. OggParserTest#setUp()

Project: ExoPlayer
Source File: OggParserTest.java
View license
@Override
public void setUp() throws Exception {
    super.setUp();
    random = new Random(0);
    oggParser = new OggParser();
    scratch = new ParsableByteArray(new byte[255 * 255], 0);
}

16. VorbisUtilTest#testVerifyVorbisHeaderCapturePatternInvalidPattern()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testVerifyVorbisHeaderCapturePatternInvalidPattern() {
    ParsableByteArray header = new ParsableByteArray(new byte[] { 0x01, 'x', 'v', 'o', 'r', 'b', 'i', 's' });
    try {
        VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, header, false);
        fail();
    } catch (ParserException e) {
        assertEquals("expected characters 'vorbis'", e.getMessage());
    }
}

17. Id3Parser#parse()

Project: ExoPlayer
Source File: Id3Parser.java
View license
@Override
public List<Id3Frame> parse(byte[] data, int size) throws ParserException {
    List<Id3Frame> id3Frames = new ArrayList<>();
    ParsableByteArray id3Data = new ParsableByteArray(data, size);
    int id3Size = parseId3Header(id3Data);
    while (id3Size > 0) {
        int frameId0 = id3Data.readUnsignedByte();
        int frameId1 = id3Data.readUnsignedByte();
        int frameId2 = id3Data.readUnsignedByte();
        int frameId3 = id3Data.readUnsignedByte();
        int frameSize = id3Data.readSynchSafeInt();
        if (frameSize <= 1) {
            break;
        }
        // Skip frame flags.
        id3Data.skipBytes(2);
        try {
            Id3Frame frame;
            if (frameId0 == 'T' && frameId1 == 'X' && frameId2 == 'X' && frameId3 == 'X') {
                frame = parseTxxxFrame(id3Data, frameSize);
            } else if (frameId0 == 'P' && frameId1 == 'R' && frameId2 == 'I' && frameId3 == 'V') {
                frame = parsePrivFrame(id3Data, frameSize);
            } else if (frameId0 == 'G' && frameId1 == 'E' && frameId2 == 'O' && frameId3 == 'B') {
                frame = parseGeobFrame(id3Data, frameSize);
            } else if (frameId0 == 'A' && frameId1 == 'P' && frameId2 == 'I' && frameId3 == 'C') {
                frame = parseApicFrame(id3Data, frameSize);
            } else if (frameId0 == 'T') {
                String id = String.format(Locale.US, "%c%c%c%c", frameId0, frameId1, frameId2, frameId3);
                frame = parseTextInformationFrame(id3Data, frameSize, id);
            } else {
                String id = String.format(Locale.US, "%c%c%c%c", frameId0, frameId1, frameId2, frameId3);
                frame = parseBinaryFrame(id3Data, frameSize, id);
            }
            id3Frames.add(frame);
            id3Size -= frameSize + 10;
        } catch (UnsupportedEncodingException e) {
            throw new ParserException(e);
        }
    }
    return Collections.unmodifiableList(id3Frames);
}

18. WebvttExtractor#processSample()

Project: ExoPlayer
Source File: WebvttExtractor.java
View license
private void processSample() throws ParserException {
    ParsableByteArray webvttData = new ParsableByteArray(sampleData);
    // Validate the first line of the header.
    WebvttParserUtil.validateWebvttHeaderLine(webvttData);
    // Defaults to use if the header doesn't contain an X-TIMESTAMP-MAP header.
    long vttTimestampUs = 0;
    long tsTimestampUs = 0;
    // Parse the remainder of the header looking for X-TIMESTAMP-MAP.
    String line;
    while (!TextUtils.isEmpty(line = webvttData.readLine())) {
        if (line.startsWith("X-TIMESTAMP-MAP")) {
            Matcher localTimestampMatcher = LOCAL_TIMESTAMP.matcher(line);
            if (!localTimestampMatcher.find()) {
                throw new ParserException("X-TIMESTAMP-MAP doesn't contain local timestamp: " + line);
            }
            Matcher mediaTimestampMatcher = MEDIA_TIMESTAMP.matcher(line);
            if (!mediaTimestampMatcher.find()) {
                throw new ParserException("X-TIMESTAMP-MAP doesn't contain media timestamp: " + line);
            }
            vttTimestampUs = WebvttParserUtil.parseTimestampUs(localTimestampMatcher.group(1));
            tsTimestampUs = PtsTimestampAdjuster.ptsToUs(Long.parseLong(mediaTimestampMatcher.group(1)));
        }
    }
    // Find the first cue header and parse the start time.
    Matcher cueHeaderMatcher = WebvttCueParser.findNextCueHeader(webvttData);
    if (cueHeaderMatcher == null) {
        // No cues found. Don't output a sample, but still output a corresponding track.
        buildTrackOutput(0);
        return;
    }
    long firstCueTimeUs = WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(1));
    long sampleTimeUs = ptsTimestampAdjuster.adjustTimestamp(PtsTimestampAdjuster.usToPts(firstCueTimeUs + tsTimestampUs - vttTimestampUs));
    long subsampleOffsetUs = sampleTimeUs - firstCueTimeUs;
    // Output the track.
    TrackOutput trackOutput = buildTrackOutput(subsampleOffsetUs);
    // Output the sample.
    sampleDataWrapper.reset(sampleData, sampleSize);
    trackOutput.sampleData(sampleDataWrapper, sampleSize);
    trackOutput.sampleMetadata(sampleTimeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
}

19. WavHeaderReader#skipToData()

Project: ExoPlayer
Source File: WavHeaderReader.java
View license
/**
   * Skips to the data in the given WAV input stream and returns its data size. After calling, the
   * input stream's position will point to the start of sample data in the WAV.
   * <p>
   * If an exception is thrown, the input position will be left pointing to a chunk header.
   *
   * @param input Input stream to skip to the data chunk in. Its peek position must be pointing to
   *     a valid chunk header.
   * @param wavHeader WAV header to populate with data bounds.
   * @throws IOException If reading from the input fails.
   * @throws InterruptedException If interrupted while reading from input.
   * @throws ParserException If an error occurs parsing chunks.
   */
public static void skipToData(ExtractorInput input, WavHeader wavHeader) throws IOException, InterruptedException, ParserException {
    Assertions.checkNotNull(input);
    Assertions.checkNotNull(wavHeader);
    // Make sure the peek position is set to the read position before we peek the first header.
    input.resetPeekPosition();
    ParsableByteArray scratch = new ParsableByteArray(ChunkHeader.SIZE_IN_BYTES);
    // Skip all chunks until we hit the data header.
    ChunkHeader chunkHeader = ChunkHeader.peek(input, scratch);
    while (chunkHeader.id != Util.getIntegerCodeForString("data")) {
        Log.w(TAG, "Ignoring unknown WAV chunk: " + chunkHeader.id);
        long bytesToSkip = ChunkHeader.SIZE_IN_BYTES + chunkHeader.size;
        // Override size of RIFF chunk, since it describes its size as the entire file.
        if (chunkHeader.id == Util.getIntegerCodeForString("RIFF")) {
            bytesToSkip = ChunkHeader.SIZE_IN_BYTES + 4;
        }
        if (bytesToSkip > Integer.MAX_VALUE) {
            throw new ParserException("Chunk is too large (~2GB+) to skip; id: " + chunkHeader.id);
        }
        input.skipFully((int) bytesToSkip);
        chunkHeader = ChunkHeader.peek(input, scratch);
    }
    // Skip past the "data" header.
    input.skipFully(ChunkHeader.SIZE_IN_BYTES);
    wavHeader.setDataBounds(input.getPosition(), chunkHeader.size);
}

20. OggUtilTest#testPopulatePageHeaderQuiteOnExceptionLessThan27Bytes()

Project: ExoPlayer
Source File: OggUtilTest.java
View license
public void testPopulatePageHeaderQuiteOnExceptionLessThan27Bytes() throws IOException, InterruptedException {
    FakeExtractorInput input = TestData.createInput(TestUtil.createByteArray(2, 2), false);
    OggUtil.PageHeader header = new OggUtil.PageHeader();
    ParsableByteArray byteArray = new ParsableByteArray(27 + 2);
    assertFalse(populatePageHeader(input, header, byteArray, true));
}

21. AdtsExtractor#sniff()

Project: ExoPlayer
Source File: AdtsExtractor.java
View license
@Override
public boolean sniff(ExtractorInput input) throws IOException, InterruptedException {
    // Skip any ID3 headers.
    ParsableByteArray scratch = new ParsableByteArray(10);
    ParsableBitArray scratchBits = new ParsableBitArray(scratch.data);
    int startPosition = 0;
    while (true) {
        input.peekFully(scratch.data, 0, 10);
        scratch.setPosition(0);
        if (scratch.readUnsignedInt24() != ID3_TAG) {
            break;
        }
        int length = (scratch.data[6] & 0x7F) << 21 | ((scratch.data[7] & 0x7F) << 14) | ((scratch.data[8] & 0x7F) << 7) | (scratch.data[9] & 0x7F);
        startPosition += 10 + length;
        input.advancePeekPosition(length);
    }
    input.resetPeekPosition();
    input.advancePeekPosition(startPosition);
    // Try to find four or more consecutive AAC audio frames, exceeding the MPEG TS packet size.
    int headerPosition = startPosition;
    int validFramesSize = 0;
    int validFramesCount = 0;
    while (true) {
        input.peekFully(scratch.data, 0, 2);
        scratch.setPosition(0);
        int syncBytes = scratch.readUnsignedShort();
        if ((syncBytes & 0xFFF6) != 0xFFF0) {
            validFramesCount = 0;
            validFramesSize = 0;
            input.resetPeekPosition();
            if (++headerPosition - startPosition >= MAX_SNIFF_BYTES) {
                return false;
            }
            input.advancePeekPosition(headerPosition);
        } else {
            if (++validFramesCount >= 4 && validFramesSize > 188) {
                return true;
            }
            // Skip the frame.
            input.peekFully(scratch.data, 0, 4);
            scratchBits.setPosition(14);
            int frameSize = scratchBits.readBits(13);
            // Either the stream is malformed OR we're not parsing an ADTS stream.
            if (frameSize <= 6) {
                return false;
            }
            input.advancePeekPosition(frameSize - 6);
            validFramesSize += frameSize;
        }
    }
}

22. Sniffer#sniffInternal()

Project: ExoPlayer
Source File: Sniffer.java
View license
private static boolean sniffInternal(ExtractorInput input, boolean fragmented) throws IOException, InterruptedException {
    long inputLength = input.getLength();
    int bytesToSearch = (int) (inputLength == C.LENGTH_UNBOUNDED || 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;
        input.peekFully(buffer.data, 0, headerSize);
        buffer.setPosition(0);
        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);
            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;
            }
            if (buffer.capacity() < atomDataSize) {
                buffer.reset(new byte[atomDataSize], 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;
}

23. VorbisReaderTest#setUp()

Project: ExoPlayer
Source File: VorbisReaderTest.java
View license
@Override
public void setUp() throws Exception {
    super.setUp();
    extractor = new VorbisReader();
    scratch = new ParsableByteArray(new byte[255 * 255], 0);
}

24. VorbisUtilTest#testReadCommentHeader()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testReadCommentHeader() throws ParserException {
    byte[] data = TestData.getCommentHeaderDataUTF8();
    ParsableByteArray headerData = new ParsableByteArray(data, data.length);
    VorbisUtil.CommentHeader commentHeader = VorbisUtil.readVorbisCommentHeader(headerData);
    assertEquals("Xiph.Org libVorbis I 20120203 (Omnipresent)", commentHeader.vendor);
    assertEquals(3, commentHeader.comments.length);
    assertEquals("ALBUM=дц", commentHeader.comments[0]);
    assertEquals("TITLE=A sample song", commentHeader.comments[1]);
    assertEquals("ARTIST=Google", commentHeader.comments[2]);
}

25. VorbisUtilTest#testVerifyVorbisHeaderCapturePattern()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testVerifyVorbisHeaderCapturePattern() throws ParserException {
    ParsableByteArray header = new ParsableByteArray(new byte[] { 0x01, 'v', 'o', 'r', 'b', 'i', 's' });
    assertEquals(true, VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, header, false));
}

26. VorbisUtilTest#testVerifyVorbisHeaderCapturePatternInvalidHeader()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testVerifyVorbisHeaderCapturePatternInvalidHeader() {
    ParsableByteArray header = new ParsableByteArray(new byte[] { 0x01, 'v', 'o', 'r', 'b', 'i', 's' });
    try {
        VorbisUtil.verifyVorbisHeaderCapturePattern(0x99, header, false);
        fail();
    } catch (ParserException e) {
        assertEquals("expected header type 99", e.getMessage());
    }
}

27. VorbisUtilTest#testVerifyVorbisHeaderCapturePatternInvalidHeaderQuite()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testVerifyVorbisHeaderCapturePatternInvalidHeaderQuite() throws ParserException {
    ParsableByteArray header = new ParsableByteArray(new byte[] { 0x01, 'v', 'o', 'r', 'b', 'i', 's' });
    assertFalse(VorbisUtil.verifyVorbisHeaderCapturePattern(0x99, header, true));
}

28. Id3Util#parseId3()

Project: ExoPlayer
Source File: Id3Util.java
View license
/**
   * Peeks data from the input and parses ID3 metadata.
   *
   * @param input The {@link ExtractorInput} from which data should be peeked.
   * @return The gapless playback information, if present and non-zero. {@code null} otherwise.
   * @throws IOException If an error occurred peeking from the input.
   * @throws InterruptedException If the thread was interrupted.
   */
public static GaplessInfo parseId3(ExtractorInput input) throws IOException, InterruptedException {
    ParsableByteArray scratch = new ParsableByteArray(10);
    int peekedId3Bytes = 0;
    GaplessInfo metadata = null;
    while (true) {
        input.peekFully(scratch.data, 0, 10);
        scratch.setPosition(0);
        if (scratch.readUnsignedInt24() != ID3_TAG) {
            break;
        }
        int majorVersion = scratch.readUnsignedByte();
        int minorVersion = scratch.readUnsignedByte();
        int flags = scratch.readUnsignedByte();
        int length = scratch.readSynchSafeInt();
        if (metadata == null && canParseMetadata(majorVersion, minorVersion, flags, length)) {
            byte[] frame = new byte[length];
            input.peekFully(frame, 0, length);
            metadata = parseGaplessInfo(new ParsableByteArray(frame), majorVersion, flags);
        } else {
            input.advancePeekPosition(length);
        }
        peekedId3Bytes += 10 + length;
    }
    input.resetPeekPosition();
    input.advancePeekPosition(peekedId3Bytes);
    return metadata;
}

29. AdtsReaderTest#testSkipToNextSampleResetsState()

Project: ExoPlayer
Source File: AdtsReaderTest.java
View license
public void testSkipToNextSampleResetsState() throws Exception {
    data = new ParsableByteArray(TestUtil.joinByteArrays(ADTS_HEADER, ADTS_CONTENT, // Adts sample missing the first sync byte
    Arrays.copyOfRange(ADTS_HEADER, 1, ADTS_HEADER.length), ADTS_CONTENT));
    feed();
    assertSampleCounts(0, 1);
    adtsOutput.assertSample(0, ADTS_CONTENT, 0, C.SAMPLE_FLAG_SYNC, null);
}

30. AdtsReaderTest#setUp()

Project: ExoPlayer
Source File: AdtsReaderTest.java
View license
@Override
protected void setUp() throws Exception {
    adtsOutput = new FakeTrackOutput();
    id3Output = new FakeTrackOutput();
    adtsReader = new AdtsReader(adtsOutput, id3Output);
    data = new ParsableByteArray(TEST_DATA);
    firstFeed = true;
}

31. VorbisUtilTest#testVerifyVorbisHeaderCapturePatternQuiteInvalidPatternQuite()

Project: ExoPlayer
Source File: VorbisUtilTest.java
View license
public void testVerifyVorbisHeaderCapturePatternQuiteInvalidPatternQuite() throws ParserException {
    ParsableByteArray header = new ParsableByteArray(new byte[] { 0x01, 'x', 'v', 'o', 'r', 'b', 'i', 's' });
    assertFalse(VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, header, true));
}