Search in sources :

Example 6 with ParserException

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

Example 7 with ParserException

use of com.google.android.exoplayer2.ParserException in project ExoPlayer by google.

the class Mp4Extractor method processMoovAtom.

/**
   * Updates the stored track metadata to reflect the contents of the specified moov atom.
   */
private void processMoovAtom(ContainerAtom moov) throws ParserException {
    long durationUs = C.TIME_UNSET;
    List<Mp4Track> tracks = new ArrayList<>();
    long earliestSampleOffset = Long.MAX_VALUE;
    Metadata metadata = null;
    GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
    Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
    if (udta != null) {
        metadata = AtomParsers.parseUdta(udta, isQuickTime);
        if (metadata != null) {
            gaplessInfoHolder.setFromMetadata(metadata);
        }
    }
    for (int i = 0; i < moov.containerChildren.size(); i++) {
        Atom.ContainerAtom atom = moov.containerChildren.get(i);
        if (atom.type != Atom.TYPE_trak) {
            continue;
        }
        Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), C.TIME_UNSET, null, isQuickTime);
        if (track == null) {
            continue;
        }
        Atom.ContainerAtom stblAtom = atom.getContainerAtomOfType(Atom.TYPE_mdia).getContainerAtomOfType(Atom.TYPE_minf).getContainerAtomOfType(Atom.TYPE_stbl);
        TrackSampleTable trackSampleTable = AtomParsers.parseStbl(track, stblAtom, gaplessInfoHolder);
        if (trackSampleTable.sampleCount == 0) {
            continue;
        }
        Mp4Track mp4Track = new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type));
        // Each sample has up to three bytes of overhead for the start code that replaces its length.
        // Allow ten source samples per output sample, like the platform extractor.
        int maxInputSize = trackSampleTable.maximumSize + 3 * 10;
        Format format = track.format.copyWithMaxInputSize(maxInputSize);
        if (track.type == C.TRACK_TYPE_AUDIO) {
            if (gaplessInfoHolder.hasGaplessInfo()) {
                format = format.copyWithGaplessInfo(gaplessInfoHolder.encoderDelay, gaplessInfoHolder.encoderPadding);
            }
            if (metadata != null) {
                format = format.copyWithMetadata(metadata);
            }
        }
        mp4Track.trackOutput.format(format);
        durationUs = Math.max(durationUs, track.durationUs);
        tracks.add(mp4Track);
        long firstSampleOffset = trackSampleTable.offsets[0];
        if (firstSampleOffset < earliestSampleOffset) {
            earliestSampleOffset = firstSampleOffset;
        }
    }
    this.durationUs = durationUs;
    this.tracks = tracks.toArray(new Mp4Track[tracks.size()]);
    extractorOutput.endTracks();
    extractorOutput.seekMap(this);
}
Also used : ArrayList(java.util.ArrayList) Metadata(com.google.android.exoplayer2.metadata.Metadata) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) Format(com.google.android.exoplayer2.Format) GaplessInfoHolder(com.google.android.exoplayer2.extractor.GaplessInfoHolder)

Example 8 with ParserException

use of com.google.android.exoplayer2.ParserException in project ExoPlayer by google.

the class Mp4Extractor method processAtomEnded.

private void processAtomEnded(long atomEndPosition) throws ParserException {
    while (!containerAtoms.isEmpty() && containerAtoms.peek().endPosition == atomEndPosition) {
        Atom.ContainerAtom containerAtom = containerAtoms.pop();
        if (containerAtom.type == Atom.TYPE_moov) {
            // We've reached the end of the moov atom. Process it and prepare to read samples.
            processMoovAtom(containerAtom);
            containerAtoms.clear();
            parserState = STATE_READING_SAMPLE;
        } else if (!containerAtoms.isEmpty()) {
            containerAtoms.peek().add(containerAtom);
        }
    }
    if (parserState != STATE_READING_SAMPLE) {
        enterReadingAtomHeaderState();
    }
}
Also used : ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom)

Example 9 with ParserException

use of com.google.android.exoplayer2.ParserException in project ExoPlayer by google.

the class VideoTagPayloadReader method parsePayload.

@Override
protected void parsePayload(ParsableByteArray data, long timeUs) throws ParserException {
    int packetType = data.readUnsignedByte();
    int compositionTimeMs = data.readUnsignedInt24();
    timeUs += compositionTimeMs * 1000L;
    // Parse avc sequence header in case this was not done before.
    if (packetType == AVC_PACKET_TYPE_SEQUENCE_HEADER && !hasOutputFormat) {
        ParsableByteArray videoSequence = new ParsableByteArray(new byte[data.bytesLeft()]);
        data.readBytes(videoSequence.data, 0, data.bytesLeft());
        AvcConfig avcConfig = AvcConfig.parse(videoSequence);
        nalUnitLengthFieldLength = avcConfig.nalUnitLengthFieldLength;
        // Construct and output the format.
        Format format = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264, null, Format.NO_VALUE, Format.NO_VALUE, avcConfig.width, avcConfig.height, Format.NO_VALUE, avcConfig.initializationData, Format.NO_VALUE, avcConfig.pixelWidthAspectRatio, null);
        output.format(format);
        hasOutputFormat = true;
    } else if (packetType == AVC_PACKET_TYPE_AVC_NALU) {
        // TODO: Deduplicate with Mp4Extractor.
        // Zero the top three bytes of the array that we'll use to decode nal unit lengths, in case
        // they're only 1 or 2 bytes long.
        byte[] nalLengthData = nalLength.data;
        nalLengthData[0] = 0;
        nalLengthData[1] = 0;
        nalLengthData[2] = 0;
        int nalUnitLengthFieldLengthDiff = 4 - nalUnitLengthFieldLength;
        // NAL units are length delimited, but the decoder requires start code delimited units.
        // Loop until we've written the sample to the track output, replacing length delimiters with
        // start codes as we encounter them.
        int bytesWritten = 0;
        int bytesToWrite;
        while (data.bytesLeft() > 0) {
            // Read the NAL length so that we know where we find the next one.
            data.readBytes(nalLength.data, nalUnitLengthFieldLengthDiff, nalUnitLengthFieldLength);
            nalLength.setPosition(0);
            bytesToWrite = nalLength.readUnsignedIntToInt();
            // Write a start code for the current NAL unit.
            nalStartCode.setPosition(0);
            output.sampleData(nalStartCode, 4);
            bytesWritten += 4;
            // Write the payload of the NAL unit.
            output.sampleData(data, bytesToWrite);
            bytesWritten += bytesToWrite;
        }
        output.sampleMetadata(timeUs, frameType == VIDEO_FRAME_KEYFRAME ? C.BUFFER_FLAG_KEY_FRAME : 0, bytesWritten, 0, null);
    }
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) Format(com.google.android.exoplayer2.Format) AvcConfig(com.google.android.exoplayer2.video.AvcConfig)

Example 10 with ParserException

use of com.google.android.exoplayer2.ParserException in project ExoPlayer by google.

the class MatroskaExtractor method startMasterElement.

/* package */
void startMasterElement(int id, long contentPosition, long contentSize) throws ParserException {
    switch(id) {
        case ID_SEGMENT:
            if (segmentContentPosition != C.POSITION_UNSET && segmentContentPosition != contentPosition) {
                throw new ParserException("Multiple Segment elements not supported");
            }
            segmentContentPosition = contentPosition;
            segmentContentSize = contentSize;
            break;
        case ID_SEEK:
            seekEntryId = UNSET_ENTRY_ID;
            seekEntryPosition = C.POSITION_UNSET;
            break;
        case ID_CUES:
            cueTimesUs = new LongArray();
            cueClusterPositions = new LongArray();
            break;
        case ID_CUE_POINT:
            seenClusterPositionForCurrentCuePoint = false;
            break;
        case ID_CLUSTER:
            if (!sentSeekMap) {
                // We need to build cues before parsing the cluster.
                if (cuesContentPosition != C.POSITION_UNSET) {
                    // We know where the Cues element is located. Seek to request it.
                    seekForCues = true;
                } else {
                    // We don't know where the Cues element is located. It's most likely omitted. Allow
                    // playback, but disable seeking.
                    extractorOutput.seekMap(new SeekMap.Unseekable(durationUs));
                    sentSeekMap = true;
                }
            }
            break;
        case ID_BLOCK_GROUP:
            sampleSeenReferenceBlock = false;
            break;
        case ID_CONTENT_ENCODING:
            // TODO: check and fail if more than one content encoding is present.
            break;
        case ID_CONTENT_ENCRYPTION:
            currentTrack.hasContentEncryption = true;
            break;
        case ID_TRACK_ENTRY:
            currentTrack = new Track();
            break;
        default:
            break;
    }
}
Also used : LongArray(com.google.android.exoplayer2.util.LongArray) ParserException(com.google.android.exoplayer2.ParserException) SeekMap(com.google.android.exoplayer2.extractor.SeekMap)

Aggregations

ParserException (com.google.android.exoplayer2.ParserException)23 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)14 ContainerAtom (com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom)4 ArrayList (java.util.ArrayList)4 Format (com.google.android.exoplayer2.Format)3 DrmInitData (com.google.android.exoplayer2.drm.DrmInitData)3 TrackOutput (com.google.android.exoplayer2.extractor.TrackOutput)3 XmlPullParserException (org.xmlpull.v1.XmlPullParserException)3 SeekMap (com.google.android.exoplayer2.extractor.SeekMap)2 LeafAtom (com.google.android.exoplayer2.extractor.mp4.Atom.LeafAtom)2 AvcConfig (com.google.android.exoplayer2.video.AvcConfig)2 Matcher (java.util.regex.Matcher)2 XmlPullParser (org.xmlpull.v1.XmlPullParser)2 Point (android.graphics.Point)1 Uri (android.net.Uri)1 Pair (android.util.Pair)1 SparseArray (android.util.SparseArray)1 SchemeData (com.google.android.exoplayer2.drm.DrmInitData.SchemeData)1 ChunkIndex (com.google.android.exoplayer2.extractor.ChunkIndex)1 GaplessInfoHolder (com.google.android.exoplayer2.extractor.GaplessInfoHolder)1