Search in sources :

Example 1 with Mp4Extractor

use of com.google.android.exoplayer2.extractor.mp4.Mp4Extractor in project ExoPlayer by google.

the class VideoTagPayloadReader method parsePayload.

@Override
protected boolean parsePayload(ParsableByteArray data, long timeUs) throws ParserException {
    int packetType = data.readUnsignedByte();
    int compositionTimeMs = data.readInt24();
    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.getData(), 0, data.bytesLeft());
        AvcConfig avcConfig = AvcConfig.parse(videoSequence);
        nalUnitLengthFieldLength = avcConfig.nalUnitLengthFieldLength;
        // Construct and output the format.
        Format format = new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).setCodecs(avcConfig.codecs).setWidth(avcConfig.width).setHeight(avcConfig.height).setPixelWidthHeightRatio(avcConfig.pixelWidthHeightRatio).setInitializationData(avcConfig.initializationData).build();
        output.format(format);
        hasOutputFormat = true;
        return false;
    } else if (packetType == AVC_PACKET_TYPE_AVC_NALU && hasOutputFormat) {
        boolean isKeyframe = frameType == VIDEO_FRAME_KEYFRAME;
        if (!hasOutputKeyframe && !isKeyframe) {
            return false;
        }
        // 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.getData();
        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.getData(), 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, isKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0, bytesWritten, 0, null);
        hasOutputKeyframe = true;
        return true;
    } else {
        return false;
    }
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) Format(com.google.android.exoplayer2.Format) AvcConfig(com.google.android.exoplayer2.video.AvcConfig)

Example 2 with Mp4Extractor

use of com.google.android.exoplayer2.extractor.mp4.Mp4Extractor in project ExoPlayer by google.

the class JpegExtractor method sniffMotionPhotoVideo.

private void sniffMotionPhotoVideo(ExtractorInput input) throws IOException {
    // Check if the file is truncated.
    boolean peekedData = input.peekFully(scratch.getData(), /* offset= */
    0, /* length= */
    1, /* allowEndOfInput= */
    true);
    if (!peekedData) {
        endReadingWithImageTrack();
    } else {
        input.resetPeekPosition();
        if (mp4Extractor == null) {
            mp4Extractor = new Mp4Extractor();
        }
        mp4ExtractorStartOffsetExtractorInput = new StartOffsetExtractorInput(input, mp4StartPosition);
        if (mp4Extractor.sniff(mp4ExtractorStartOffsetExtractorInput)) {
            mp4Extractor.init(new StartOffsetExtractorOutput(mp4StartPosition, checkNotNull(extractorOutput)));
            startReadingMotionPhoto();
        } else {
            endReadingWithImageTrack();
        }
    }
}
Also used : Mp4Extractor(com.google.android.exoplayer2.extractor.mp4.Mp4Extractor)

Example 3 with Mp4Extractor

use of com.google.android.exoplayer2.extractor.mp4.Mp4Extractor in project ExoPlayer by google.

the class MatroskaExtractor method writeSampleData.

/**
 * Writes data for a single sample to the track output.
 *
 * @param input The input from which to read sample data.
 * @param track The track to output the sample to.
 * @param size The size of the sample data on the input side.
 * @return The final size of the written sample.
 * @throws IOException If an error occurs reading from the input.
 */
@RequiresNonNull("#2.output")
private int writeSampleData(ExtractorInput input, Track track, int size) throws IOException {
    if (CODEC_ID_SUBRIP.equals(track.codecId)) {
        writeSubtitleSampleData(input, SUBRIP_PREFIX, size);
        return finishWriteSampleData();
    } else if (CODEC_ID_ASS.equals(track.codecId)) {
        writeSubtitleSampleData(input, SSA_PREFIX, size);
        return finishWriteSampleData();
    } else if (CODEC_ID_VTT.equals(track.codecId)) {
        writeSubtitleSampleData(input, VTT_PREFIX, size);
        return finishWriteSampleData();
    }
    TrackOutput output = track.output;
    if (!sampleEncodingHandled) {
        if (track.hasContentEncryption) {
            // If the sample is encrypted, read its encryption signal byte and set the IV size.
            // Clear the encrypted flag.
            blockFlags &= ~C.BUFFER_FLAG_ENCRYPTED;
            if (!sampleSignalByteRead) {
                input.readFully(scratch.getData(), 0, 1);
                sampleBytesRead++;
                if ((scratch.getData()[0] & 0x80) == 0x80) {
                    throw ParserException.createForMalformedContainer("Extension bit is set in signal byte", /* cause= */
                    null);
                }
                sampleSignalByte = scratch.getData()[0];
                sampleSignalByteRead = true;
            }
            boolean isEncrypted = (sampleSignalByte & 0x01) == 0x01;
            if (isEncrypted) {
                boolean hasSubsampleEncryption = (sampleSignalByte & 0x02) == 0x02;
                blockFlags |= C.BUFFER_FLAG_ENCRYPTED;
                if (!sampleInitializationVectorRead) {
                    input.readFully(encryptionInitializationVector.getData(), 0, ENCRYPTION_IV_SIZE);
                    sampleBytesRead += ENCRYPTION_IV_SIZE;
                    sampleInitializationVectorRead = true;
                    // Write the signal byte, containing the IV size and the subsample encryption flag.
                    scratch.getData()[0] = (byte) (ENCRYPTION_IV_SIZE | (hasSubsampleEncryption ? 0x80 : 0x00));
                    scratch.setPosition(0);
                    output.sampleData(scratch, 1, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
                    sampleBytesWritten++;
                    // Write the IV.
                    encryptionInitializationVector.setPosition(0);
                    output.sampleData(encryptionInitializationVector, ENCRYPTION_IV_SIZE, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
                    sampleBytesWritten += ENCRYPTION_IV_SIZE;
                }
                if (hasSubsampleEncryption) {
                    if (!samplePartitionCountRead) {
                        input.readFully(scratch.getData(), 0, 1);
                        sampleBytesRead++;
                        scratch.setPosition(0);
                        samplePartitionCount = scratch.readUnsignedByte();
                        samplePartitionCountRead = true;
                    }
                    int samplePartitionDataSize = samplePartitionCount * 4;
                    scratch.reset(samplePartitionDataSize);
                    input.readFully(scratch.getData(), 0, samplePartitionDataSize);
                    sampleBytesRead += samplePartitionDataSize;
                    short subsampleCount = (short) (1 + (samplePartitionCount / 2));
                    int subsampleDataSize = 2 + 6 * subsampleCount;
                    if (encryptionSubsampleDataBuffer == null || encryptionSubsampleDataBuffer.capacity() < subsampleDataSize) {
                        encryptionSubsampleDataBuffer = ByteBuffer.allocate(subsampleDataSize);
                    }
                    encryptionSubsampleDataBuffer.position(0);
                    encryptionSubsampleDataBuffer.putShort(subsampleCount);
                    // Loop through the partition offsets and write out the data in the way ExoPlayer
                    // wants it (ISO 23001-7 Part 7):
                    // 2 bytes - sub sample count.
                    // for each sub sample:
                    // 2 bytes - clear data size.
                    // 4 bytes - encrypted data size.
                    int partitionOffset = 0;
                    for (int i = 0; i < samplePartitionCount; i++) {
                        int previousPartitionOffset = partitionOffset;
                        partitionOffset = scratch.readUnsignedIntToInt();
                        if ((i % 2) == 0) {
                            encryptionSubsampleDataBuffer.putShort((short) (partitionOffset - previousPartitionOffset));
                        } else {
                            encryptionSubsampleDataBuffer.putInt(partitionOffset - previousPartitionOffset);
                        }
                    }
                    int finalPartitionSize = size - sampleBytesRead - partitionOffset;
                    if ((samplePartitionCount % 2) == 1) {
                        encryptionSubsampleDataBuffer.putInt(finalPartitionSize);
                    } else {
                        encryptionSubsampleDataBuffer.putShort((short) finalPartitionSize);
                        encryptionSubsampleDataBuffer.putInt(0);
                    }
                    encryptionSubsampleData.reset(encryptionSubsampleDataBuffer.array(), subsampleDataSize);
                    output.sampleData(encryptionSubsampleData, subsampleDataSize, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION);
                    sampleBytesWritten += subsampleDataSize;
                }
            }
        } else if (track.sampleStrippedBytes != null) {
            // If the sample has header stripping, prepare to read/output the stripped bytes first.
            sampleStrippedBytes.reset(track.sampleStrippedBytes, track.sampleStrippedBytes.length);
        }
        if (track.maxBlockAdditionId > 0) {
            blockFlags |= C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA;
            blockAdditionalData.reset(/* limit= */
            0);
            // If there is supplemental data, the structure of the sample data is:
            // sample size (4 bytes) || sample data || supplemental data
            scratch.reset(/* limit= */
            4);
            scratch.getData()[0] = (byte) ((size >> 24) & 0xFF);
            scratch.getData()[1] = (byte) ((size >> 16) & 0xFF);
            scratch.getData()[2] = (byte) ((size >> 8) & 0xFF);
            scratch.getData()[3] = (byte) (size & 0xFF);
            output.sampleData(scratch, 4, TrackOutput.SAMPLE_DATA_PART_SUPPLEMENTAL);
            sampleBytesWritten += 4;
        }
        sampleEncodingHandled = true;
    }
    size += sampleStrippedBytes.limit();
    if (CODEC_ID_H264.equals(track.codecId) || CODEC_ID_H265.equals(track.codecId)) {
        // 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.getData();
        nalLengthData[0] = 0;
        nalLengthData[1] = 0;
        nalLengthData[2] = 0;
        int nalUnitLengthFieldLength = track.nalUnitLengthFieldLength;
        int nalUnitLengthFieldLengthDiff = 4 - track.nalUnitLengthFieldLength;
        // start codes as we encounter them.
        while (sampleBytesRead < size) {
            if (sampleCurrentNalBytesRemaining == 0) {
                // Read the NAL length so that we know where we find the next one.
                writeToTarget(input, nalLengthData, nalUnitLengthFieldLengthDiff, nalUnitLengthFieldLength);
                sampleBytesRead += nalUnitLengthFieldLength;
                nalLength.setPosition(0);
                sampleCurrentNalBytesRemaining = nalLength.readUnsignedIntToInt();
                // Write a start code for the current NAL unit.
                nalStartCode.setPosition(0);
                output.sampleData(nalStartCode, 4);
                sampleBytesWritten += 4;
            } else {
                // Write the payload of the NAL unit.
                int bytesWritten = writeToOutput(input, output, sampleCurrentNalBytesRemaining);
                sampleBytesRead += bytesWritten;
                sampleBytesWritten += bytesWritten;
                sampleCurrentNalBytesRemaining -= bytesWritten;
            }
        }
    } else {
        if (track.trueHdSampleRechunker != null) {
            checkState(sampleStrippedBytes.limit() == 0);
            track.trueHdSampleRechunker.startSample(input);
        }
        while (sampleBytesRead < size) {
            int bytesWritten = writeToOutput(input, output, size - sampleBytesRead);
            sampleBytesRead += bytesWritten;
            sampleBytesWritten += bytesWritten;
        }
    }
    if (CODEC_ID_VORBIS.equals(track.codecId)) {
        // Vorbis decoder in android MediaCodec [1] expects the last 4 bytes of the sample to be the
        // number of samples in the current page. This definition holds good only for Ogg and
        // irrelevant for Matroska. So we always set this to -1 (the decoder will ignore this value if
        // we set it to -1). The android platform media extractor [2] does the same.
        // [1]
        // https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp#314
        // [2]
        // https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/media/libstagefright/NuMediaExtractor.cpp#474
        vorbisNumPageSamples.setPosition(0);
        output.sampleData(vorbisNumPageSamples, 4);
        sampleBytesWritten += 4;
    }
    return finishWriteSampleData();
}
Also used : TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput) RequiresNonNull(org.checkerframework.checker.nullness.qual.RequiresNonNull)

Example 4 with Mp4Extractor

use of com.google.android.exoplayer2.extractor.mp4.Mp4Extractor in project ExoPlayer by google.

the class DefaultExtractorsFactory method addExtractorsForFileType.

private void addExtractorsForFileType(@FileTypes.Type int fileType, List<Extractor> extractors) {
    switch(fileType) {
        case FileTypes.AC3:
            extractors.add(new Ac3Extractor());
            break;
        case FileTypes.AC4:
            extractors.add(new Ac4Extractor());
            break;
        case FileTypes.ADTS:
            extractors.add(new AdtsExtractor(adtsFlags | (constantBitrateSeekingEnabled ? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING : 0) | (constantBitrateSeekingAlwaysEnabled ? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS : 0)));
            break;
        case FileTypes.AMR:
            extractors.add(new AmrExtractor(amrFlags | (constantBitrateSeekingEnabled ? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING : 0) | (constantBitrateSeekingAlwaysEnabled ? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS : 0)));
            break;
        case FileTypes.FLAC:
            @Nullable Extractor flacExtractor = FLAC_EXTENSION_LOADER.getExtractor(flacFlags);
            if (flacExtractor != null) {
                extractors.add(flacExtractor);
            } else {
                extractors.add(new FlacExtractor(flacFlags));
            }
            break;
        case FileTypes.FLV:
            extractors.add(new FlvExtractor());
            break;
        case FileTypes.MATROSKA:
            extractors.add(new MatroskaExtractor(matroskaFlags));
            break;
        case FileTypes.MP3:
            extractors.add(new Mp3Extractor(mp3Flags | (constantBitrateSeekingEnabled ? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING : 0) | (constantBitrateSeekingAlwaysEnabled ? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS : 0)));
            break;
        case FileTypes.MP4:
            extractors.add(new FragmentedMp4Extractor(fragmentedMp4Flags));
            extractors.add(new Mp4Extractor(mp4Flags));
            break;
        case FileTypes.OGG:
            extractors.add(new OggExtractor());
            break;
        case FileTypes.PS:
            extractors.add(new PsExtractor());
            break;
        case FileTypes.TS:
            extractors.add(new TsExtractor(tsMode, tsFlags, tsTimestampSearchBytes));
            break;
        case FileTypes.WAV:
            extractors.add(new WavExtractor());
            break;
        case FileTypes.JPEG:
            extractors.add(new JpegExtractor());
            break;
        case FileTypes.WEBVTT:
        case FileTypes.UNKNOWN:
        default:
            break;
    }
}
Also used : FragmentedMp4Extractor(com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor) JpegExtractor(com.google.android.exoplayer2.extractor.jpeg.JpegExtractor) Ac4Extractor(com.google.android.exoplayer2.extractor.ts.Ac4Extractor) AdtsExtractor(com.google.android.exoplayer2.extractor.ts.AdtsExtractor) Mp3Extractor(com.google.android.exoplayer2.extractor.mp3.Mp3Extractor) MatroskaExtractor(com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor) TsExtractor(com.google.android.exoplayer2.extractor.ts.TsExtractor) FlacExtractor(com.google.android.exoplayer2.extractor.flac.FlacExtractor) AmrExtractor(com.google.android.exoplayer2.extractor.amr.AmrExtractor) FragmentedMp4Extractor(com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor) Mp4Extractor(com.google.android.exoplayer2.extractor.mp4.Mp4Extractor) PsExtractor(com.google.android.exoplayer2.extractor.ts.PsExtractor) OggExtractor(com.google.android.exoplayer2.extractor.ogg.OggExtractor) WavExtractor(com.google.android.exoplayer2.extractor.wav.WavExtractor) FragmentedMp4Extractor(com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor) PsExtractor(com.google.android.exoplayer2.extractor.ts.PsExtractor) FlvExtractor(com.google.android.exoplayer2.extractor.flv.FlvExtractor) OggExtractor(com.google.android.exoplayer2.extractor.ogg.OggExtractor) TsExtractor(com.google.android.exoplayer2.extractor.ts.TsExtractor) JpegExtractor(com.google.android.exoplayer2.extractor.jpeg.JpegExtractor) Mp4Extractor(com.google.android.exoplayer2.extractor.mp4.Mp4Extractor) Mp3Extractor(com.google.android.exoplayer2.extractor.mp3.Mp3Extractor) Ac4Extractor(com.google.android.exoplayer2.extractor.ts.Ac4Extractor) WavExtractor(com.google.android.exoplayer2.extractor.wav.WavExtractor) AdtsExtractor(com.google.android.exoplayer2.extractor.ts.AdtsExtractor) Ac3Extractor(com.google.android.exoplayer2.extractor.ts.Ac3Extractor) AmrExtractor(com.google.android.exoplayer2.extractor.amr.AmrExtractor) MatroskaExtractor(com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor) FlacExtractor(com.google.android.exoplayer2.extractor.flac.FlacExtractor) FlvExtractor(com.google.android.exoplayer2.extractor.flv.FlvExtractor) Ac3Extractor(com.google.android.exoplayer2.extractor.ts.Ac3Extractor) Nullable(androidx.annotation.Nullable)

Aggregations

Mp4Extractor (com.google.android.exoplayer2.extractor.mp4.Mp4Extractor)2 Nullable (androidx.annotation.Nullable)1 Format (com.google.android.exoplayer2.Format)1 TrackOutput (com.google.android.exoplayer2.extractor.TrackOutput)1 AmrExtractor (com.google.android.exoplayer2.extractor.amr.AmrExtractor)1 FlacExtractor (com.google.android.exoplayer2.extractor.flac.FlacExtractor)1 FlvExtractor (com.google.android.exoplayer2.extractor.flv.FlvExtractor)1 JpegExtractor (com.google.android.exoplayer2.extractor.jpeg.JpegExtractor)1 MatroskaExtractor (com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor)1 Mp3Extractor (com.google.android.exoplayer2.extractor.mp3.Mp3Extractor)1 FragmentedMp4Extractor (com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor)1 OggExtractor (com.google.android.exoplayer2.extractor.ogg.OggExtractor)1 Ac3Extractor (com.google.android.exoplayer2.extractor.ts.Ac3Extractor)1 Ac4Extractor (com.google.android.exoplayer2.extractor.ts.Ac4Extractor)1 AdtsExtractor (com.google.android.exoplayer2.extractor.ts.AdtsExtractor)1 PsExtractor (com.google.android.exoplayer2.extractor.ts.PsExtractor)1 TsExtractor (com.google.android.exoplayer2.extractor.ts.TsExtractor)1 WavExtractor (com.google.android.exoplayer2.extractor.wav.WavExtractor)1 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)1 AvcConfig (com.google.android.exoplayer2.video.AvcConfig)1