Search in sources :

Example 1 with TrackOutput

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

the class FragmentedMp4Extractor method readSample.

/**
   * Attempts to extract the next sample in the current mdat atom.
   * <p>
   * If there are no more samples in the current mdat atom then the parser state is transitioned
   * to {@link #STATE_READING_ATOM_HEADER} and {@code false} is returned.
   * <p>
   * It is possible for a sample to be extracted in part in the case that an exception is thrown. In
   * this case the method can be called again to extract the remainder of the sample.
   *
   * @param input The {@link ExtractorInput} from which to read data.
   * @return Whether a sample was extracted.
   * @throws IOException If an error occurs reading from the input.
   * @throws InterruptedException If the thread is interrupted.
   */
private boolean readSample(ExtractorInput input) throws IOException, InterruptedException {
    if (parserState == STATE_READING_SAMPLE_START) {
        if (currentTrackBundle == null) {
            TrackBundle currentTrackBundle = getNextFragmentRun(trackBundles);
            if (currentTrackBundle == null) {
                // We've run out of samples in the current mdat. Discard any trailing data and prepare to
                // read the header of the next atom.
                int bytesToSkip = (int) (endOfMdatPosition - input.getPosition());
                if (bytesToSkip < 0) {
                    throw new ParserException("Offset to end of mdat was negative.");
                }
                input.skipFully(bytesToSkip);
                enterReadingAtomHeaderState();
                return false;
            }
            long nextDataPosition = currentTrackBundle.fragment.trunDataPosition[currentTrackBundle.currentTrackRunIndex];
            // We skip bytes preceding the next sample to read.
            int bytesToSkip = (int) (nextDataPosition - input.getPosition());
            if (bytesToSkip < 0) {
                // Assume the sample data must be contiguous in the mdat with no preceding data.
                Log.w(TAG, "Ignoring negative offset to sample data.");
                bytesToSkip = 0;
            }
            input.skipFully(bytesToSkip);
            this.currentTrackBundle = currentTrackBundle;
        }
        sampleSize = currentTrackBundle.fragment.sampleSizeTable[currentTrackBundle.currentSampleIndex];
        if (currentTrackBundle.fragment.definesEncryptionData) {
            sampleBytesWritten = appendSampleEncryptionData(currentTrackBundle);
            sampleSize += sampleBytesWritten;
        } else {
            sampleBytesWritten = 0;
        }
        if (currentTrackBundle.track.sampleTransformation == Track.TRANSFORMATION_CEA608_CDAT) {
            sampleSize -= Atom.HEADER_SIZE;
            input.skipFully(Atom.HEADER_SIZE);
        }
        parserState = STATE_READING_SAMPLE_CONTINUE;
        sampleCurrentNalBytesRemaining = 0;
    }
    TrackFragment fragment = currentTrackBundle.fragment;
    Track track = currentTrackBundle.track;
    TrackOutput output = currentTrackBundle.output;
    int sampleIndex = currentTrackBundle.currentSampleIndex;
    if (track.nalUnitLengthFieldLength != 0) {
        // 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[] nalPrefixData = nalPrefix.data;
        nalPrefixData[0] = 0;
        nalPrefixData[1] = 0;
        nalPrefixData[2] = 0;
        int nalUnitPrefixLength = track.nalUnitLengthFieldLength + 1;
        int nalUnitLengthFieldLengthDiff = 4 - track.nalUnitLengthFieldLength;
        // start codes as we encounter them.
        while (sampleBytesWritten < sampleSize) {
            if (sampleCurrentNalBytesRemaining == 0) {
                // Read the NAL length so that we know where we find the next one, and its type.
                input.readFully(nalPrefixData, nalUnitLengthFieldLengthDiff, nalUnitPrefixLength);
                nalPrefix.setPosition(0);
                sampleCurrentNalBytesRemaining = nalPrefix.readUnsignedIntToInt() - 1;
                // Write a start code for the current NAL unit.
                nalStartCode.setPosition(0);
                output.sampleData(nalStartCode, 4);
                // Write the NAL unit type byte.
                output.sampleData(nalPrefix, 1);
                processSeiNalUnitPayload = cea608TrackOutputs != null && NalUnitUtil.isNalUnitSei(track.format.sampleMimeType, nalPrefixData[4]);
                sampleBytesWritten += 5;
                sampleSize += nalUnitLengthFieldLengthDiff;
            } else {
                int writtenBytes;
                if (processSeiNalUnitPayload) {
                    // Read and write the payload of the SEI NAL unit.
                    nalBuffer.reset(sampleCurrentNalBytesRemaining);
                    input.readFully(nalBuffer.data, 0, sampleCurrentNalBytesRemaining);
                    output.sampleData(nalBuffer, sampleCurrentNalBytesRemaining);
                    writtenBytes = sampleCurrentNalBytesRemaining;
                    // Unescape and process the SEI NAL unit.
                    int unescapedLength = NalUnitUtil.unescapeStream(nalBuffer.data, nalBuffer.limit());
                    // If the format is H.265/HEVC the NAL unit header has two bytes so skip one more byte.
                    nalBuffer.setPosition(MimeTypes.VIDEO_H265.equals(track.format.sampleMimeType) ? 1 : 0);
                    nalBuffer.setLimit(unescapedLength);
                    CeaUtil.consume(fragment.getSamplePresentationTime(sampleIndex) * 1000L, nalBuffer, cea608TrackOutputs);
                } else {
                    // Write the payload of the NAL unit.
                    writtenBytes = output.sampleData(input, sampleCurrentNalBytesRemaining, false);
                }
                sampleBytesWritten += writtenBytes;
                sampleCurrentNalBytesRemaining -= writtenBytes;
            }
        }
    } else {
        while (sampleBytesWritten < sampleSize) {
            int writtenBytes = output.sampleData(input, sampleSize - sampleBytesWritten, false);
            sampleBytesWritten += writtenBytes;
        }
    }
    long sampleTimeUs = fragment.getSamplePresentationTime(sampleIndex) * 1000L;
    @C.BufferFlags int sampleFlags = (fragment.definesEncryptionData ? C.BUFFER_FLAG_ENCRYPTED : 0) | (fragment.sampleIsSyncFrameTable[sampleIndex] ? C.BUFFER_FLAG_KEY_FRAME : 0);
    int sampleDescriptionIndex = fragment.header.sampleDescriptionIndex;
    byte[] encryptionKey = null;
    if (fragment.definesEncryptionData) {
        encryptionKey = fragment.trackEncryptionBox != null ? fragment.trackEncryptionBox.keyId : track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex].keyId;
    }
    if (timestampAdjuster != null) {
        sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs);
    }
    output.sampleMetadata(sampleTimeUs, sampleFlags, sampleSize, 0, encryptionKey);
    while (!pendingMetadataSampleInfos.isEmpty()) {
        MetadataSampleInfo sampleInfo = pendingMetadataSampleInfos.removeFirst();
        pendingMetadataSampleBytes -= sampleInfo.size;
        eventMessageTrackOutput.sampleMetadata(sampleTimeUs + sampleInfo.presentationTimeDeltaUs, C.BUFFER_FLAG_KEY_FRAME, sampleInfo.size, pendingMetadataSampleBytes, null);
    }
    currentTrackBundle.currentSampleIndex++;
    currentTrackBundle.currentSampleInTrackRun++;
    if (currentTrackBundle.currentSampleInTrackRun == fragment.trunLength[currentTrackBundle.currentTrackRunIndex]) {
        currentTrackBundle.currentTrackRunIndex++;
        currentTrackBundle.currentSampleInTrackRun = 0;
        currentTrackBundle = null;
    }
    parserState = STATE_READING_SAMPLE_START;
    return true;
}
Also used : ParserException(com.google.android.exoplayer2.ParserException) TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput)

Example 2 with TrackOutput

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

the class SeiReader method createTracks.

public void createTracks(ExtractorOutput extractorOutput, TrackIdGenerator idGenerator) {
    for (int i = 0; i < outputs.length; i++) {
        idGenerator.generateNewId();
        TrackOutput output = extractorOutput.track(idGenerator.getTrackId(), C.TRACK_TYPE_TEXT);
        Format channelFormat = closedCaptionFormats.get(i);
        String channelMimeType = channelFormat.sampleMimeType;
        Assertions.checkArgument(MimeTypes.APPLICATION_CEA608.equals(channelMimeType) || MimeTypes.APPLICATION_CEA708.equals(channelMimeType), "Invalid closed caption mime type provided: " + channelMimeType);
        output.format(Format.createTextSampleFormat(idGenerator.getFormatId(), channelMimeType, null, Format.NO_VALUE, channelFormat.selectionFlags, channelFormat.language, channelFormat.accessibilityChannel, null));
        outputs[i] = output;
    }
}
Also used : Format(com.google.android.exoplayer2.Format) TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput)

Example 3 with TrackOutput

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

the class WebvttExtractor method buildTrackOutput.

private TrackOutput buildTrackOutput(long subsampleOffsetUs) {
    TrackOutput trackOutput = output.track(0, C.TRACK_TYPE_TEXT);
    trackOutput.format(Format.createTextSampleFormat(null, MimeTypes.TEXT_VTT, null, Format.NO_VALUE, 0, language, null, subsampleOffsetUs));
    output.endTracks();
    return trackOutput;
}
Also used : TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput)

Example 4 with TrackOutput

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

the class SingleSampleMediaChunk method load.

@SuppressWarnings("NonAtomicVolatileUpdate")
@Override
public void load() throws IOException, InterruptedException {
    DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded);
    try {
        // Create and open the input.
        long length = dataSource.open(loadDataSpec);
        if (length != C.LENGTH_UNSET) {
            length += bytesLoaded;
        }
        ExtractorInput extractorInput = new DefaultExtractorInput(dataSource, bytesLoaded, length);
        BaseMediaChunkOutput output = getOutput();
        output.setSampleOffsetUs(0);
        TrackOutput trackOutput = output.track(0, trackType);
        trackOutput.format(sampleFormat);
        // Load the sample data.
        int result = 0;
        while (result != C.RESULT_END_OF_INPUT) {
            bytesLoaded += result;
            result = trackOutput.sampleData(extractorInput, Integer.MAX_VALUE, true);
        }
        int sampleSize = bytesLoaded;
        trackOutput.sampleMetadata(startTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
    } finally {
        Util.closeQuietly(dataSource);
    }
    loadCompleted = true;
}
Also used : ExtractorInput(com.google.android.exoplayer2.extractor.ExtractorInput) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) DefaultExtractorInput(com.google.android.exoplayer2.extractor.DefaultExtractorInput) TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput)

Example 5 with TrackOutput

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

the class TsExtractorTest method testCustomPesReader.

public void testCustomPesReader() throws Exception {
    CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false);
    TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_NORMAL, new TimestampAdjuster(0), factory);
    FakeExtractorInput input = new FakeExtractorInput.Builder().setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample.ts")).setSimulateIOErrors(false).setSimulateUnknownLength(false).setSimulatePartialReads(false).build();
    FakeExtractorOutput output = new FakeExtractorOutput();
    tsExtractor.init(output);
    PositionHolder seekPositionHolder = new PositionHolder();
    int readResult = Extractor.RESULT_CONTINUE;
    while (readResult != Extractor.RESULT_END_OF_INPUT) {
        readResult = tsExtractor.read(input, seekPositionHolder);
    }
    CustomEsReader reader = factory.esReader;
    assertEquals(2, reader.packetsRead);
    TrackOutput trackOutput = reader.getTrackOutput();
    assertTrue(trackOutput == output.trackOutputs.get(257));
    assertEquals(Format.createTextSampleFormat("1/257", "mime", null, 0, 0, "und", null, 0), ((FakeTrackOutput) trackOutput).format);
}
Also used : FakeExtractorInput(com.google.android.exoplayer2.testutil.FakeExtractorInput) PositionHolder(com.google.android.exoplayer2.extractor.PositionHolder) TimestampAdjuster(com.google.android.exoplayer2.util.TimestampAdjuster) FakeExtractorOutput(com.google.android.exoplayer2.testutil.FakeExtractorOutput) TrackOutput(com.google.android.exoplayer2.extractor.TrackOutput) FakeTrackOutput(com.google.android.exoplayer2.testutil.FakeTrackOutput)

Aggregations

TrackOutput (com.google.android.exoplayer2.extractor.TrackOutput)11 ParserException (com.google.android.exoplayer2.ParserException)3 DefaultTrackOutput (com.google.android.exoplayer2.extractor.DefaultTrackOutput)2 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)2 Format (com.google.android.exoplayer2.Format)1 DefaultExtractorInput (com.google.android.exoplayer2.extractor.DefaultExtractorInput)1 ExtractorInput (com.google.android.exoplayer2.extractor.ExtractorInput)1 PositionHolder (com.google.android.exoplayer2.extractor.PositionHolder)1 FakeExtractorInput (com.google.android.exoplayer2.testutil.FakeExtractorInput)1 FakeExtractorOutput (com.google.android.exoplayer2.testutil.FakeExtractorOutput)1 FakeTrackOutput (com.google.android.exoplayer2.testutil.FakeTrackOutput)1 SubtitleDecoderException (com.google.android.exoplayer2.text.SubtitleDecoderException)1 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)1 TimestampAdjuster (com.google.android.exoplayer2.util.TimestampAdjuster)1 Matcher (java.util.regex.Matcher)1