Search in sources :

Example 11 with TimestampAdjuster

use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.

the class FragmentedMp4Extractor method onEmsgLeafAtomRead.

/**
 * Handles an emsg atom (defined in 23009-1).
 */
private void onEmsgLeafAtomRead(ParsableByteArray atom) {
    if (emsgTrackOutputs.length == 0) {
        return;
    }
    atom.setPosition(Atom.HEADER_SIZE);
    int fullAtom = atom.readInt();
    int version = Atom.parseFullAtomVersion(fullAtom);
    String schemeIdUri;
    String value;
    long timescale;
    // Only set if version == 0
    long presentationTimeDeltaUs = C.TIME_UNSET;
    long sampleTimeUs = C.TIME_UNSET;
    long durationMs;
    long id;
    switch(version) {
        case 0:
            schemeIdUri = checkNotNull(atom.readNullTerminatedString());
            value = checkNotNull(atom.readNullTerminatedString());
            timescale = atom.readUnsignedInt();
            presentationTimeDeltaUs = Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MICROS_PER_SECOND, timescale);
            if (segmentIndexEarliestPresentationTimeUs != C.TIME_UNSET) {
                sampleTimeUs = segmentIndexEarliestPresentationTimeUs + presentationTimeDeltaUs;
            }
            durationMs = Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale);
            id = atom.readUnsignedInt();
            break;
        case 1:
            timescale = atom.readUnsignedInt();
            sampleTimeUs = Util.scaleLargeTimestamp(atom.readUnsignedLongToLong(), C.MICROS_PER_SECOND, timescale);
            durationMs = Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale);
            id = atom.readUnsignedInt();
            schemeIdUri = checkNotNull(atom.readNullTerminatedString());
            value = checkNotNull(atom.readNullTerminatedString());
            break;
        default:
            Log.w(TAG, "Skipping unsupported emsg version: " + version);
            return;
    }
    byte[] messageData = new byte[atom.bytesLeft()];
    atom.readBytes(messageData, /*offset=*/
    0, atom.bytesLeft());
    EventMessage eventMessage = new EventMessage(schemeIdUri, value, durationMs, id, messageData);
    ParsableByteArray encodedEventMessage = new ParsableByteArray(eventMessageEncoder.encode(eventMessage));
    int sampleSize = encodedEventMessage.bytesLeft();
    // Output the sample data.
    for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
        encodedEventMessage.setPosition(0);
        emsgTrackOutput.sampleData(encodedEventMessage, sampleSize);
    }
    // Output the sample metadata.
    if (sampleTimeUs == C.TIME_UNSET) {
        // We're processing a v0 emsg atom, which contains a presentation time delta, and cannot yet
        // calculate its absolute sample timestamp. Defer outputting the metadata until we can.
        pendingMetadataSampleInfos.addLast(new MetadataSampleInfo(presentationTimeDeltaUs, /* sampleTimeIsRelative= */
        true, sampleSize));
        pendingMetadataSampleBytes += sampleSize;
    } else if (!pendingMetadataSampleInfos.isEmpty()) {
        // We also need to defer outputting metadata if pendingMetadataSampleInfos is non-empty, else
        // we will output metadata for samples in the wrong order. See:
        // https://github.com/google/ExoPlayer/issues/9996.
        pendingMetadataSampleInfos.addLast(new MetadataSampleInfo(sampleTimeUs, /* sampleTimeIsRelative= */
        false, sampleSize));
        pendingMetadataSampleBytes += sampleSize;
    } else {
        // We can output the sample metadata immediately.
        if (timestampAdjuster != null) {
            sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs);
        }
        for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
            emsgTrackOutput.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, /* offset= */
            0, null);
        }
    }
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) EventMessage(androidx.media3.extractor.metadata.emsg.EventMessage) TrackOutput(androidx.media3.extractor.TrackOutput)

Example 12 with TimestampAdjuster

use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.

the class FragmentedMp4Extractor method outputPendingMetadataSamples.

/**
 * Called immediately after outputting a non-metadata sample, to output any pending metadata
 * samples.
 *
 * @param sampleTimeUs The timestamp of the non-metadata sample that was just output.
 */
private void outputPendingMetadataSamples(long sampleTimeUs) {
    while (!pendingMetadataSampleInfos.isEmpty()) {
        MetadataSampleInfo metadataSampleInfo = pendingMetadataSampleInfos.removeFirst();
        pendingMetadataSampleBytes -= metadataSampleInfo.size;
        long metadataSampleTimeUs = metadataSampleInfo.sampleTimeUs;
        if (metadataSampleInfo.sampleTimeIsRelative) {
            // The metadata sample timestamp is relative to the timestamp of the non-metadata sample
            // that was just output. Make it absolute.
            metadataSampleTimeUs += sampleTimeUs;
        }
        if (timestampAdjuster != null) {
            metadataSampleTimeUs = timestampAdjuster.adjustSampleTimestamp(metadataSampleTimeUs);
        }
        for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
            emsgTrackOutput.sampleMetadata(metadataSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, metadataSampleInfo.size, pendingMetadataSampleBytes, null);
        }
    }
}
Also used : TrackOutput(androidx.media3.extractor.TrackOutput)

Example 13 with TimestampAdjuster

use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.

the class TsExtractor method seek.

@Override
public void seek(long position, long timeUs) {
    Assertions.checkState(mode != MODE_HLS);
    int timestampAdjustersCount = timestampAdjusters.size();
    for (int i = 0; i < timestampAdjustersCount; i++) {
        TimestampAdjuster timestampAdjuster = timestampAdjusters.get(i);
        // If the timestamp adjuster has not yet established a timestamp offset, we need to reset its
        // expected first sample timestamp to be the new seek position. Without this, the timestamp
        // adjuster would incorrectly establish its timestamp offset assuming that the first sample
        // after this seek corresponds to the start of the stream (or a previous seek position, if
        // there was one).
        boolean resetTimestampAdjuster = timestampAdjuster.getTimestampOffsetUs() == C.TIME_UNSET;
        if (!resetTimestampAdjuster) {
            long adjusterFirstSampleTimestampUs = timestampAdjuster.getFirstSampleTimestampUs();
            // Also reset the timestamp adjuster if its offset was calculated based on a non-zero
            // position in the stream (other than the position being seeked to), since in this case the
            // offset may not be accurate.
            resetTimestampAdjuster = adjusterFirstSampleTimestampUs != C.TIME_UNSET && adjusterFirstSampleTimestampUs != 0 && adjusterFirstSampleTimestampUs != timeUs;
        }
        if (resetTimestampAdjuster) {
            timestampAdjuster.reset(timeUs);
        }
    }
    if (timeUs != 0 && tsBinarySearchSeeker != null) {
        tsBinarySearchSeeker.setSeekTargetUs(timeUs);
    }
    tsPacketBuffer.reset(/* limit= */
    0);
    continuityCounters.clear();
    for (int i = 0; i < tsPayloadReaders.size(); i++) {
        tsPayloadReaders.valueAt(i).seek();
    }
    bytesSinceLastSync = 0;
}
Also used : TimestampAdjuster(androidx.media3.common.util.TimestampAdjuster)

Example 14 with TimestampAdjuster

use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.

the class TsExtractorTest method customPesReader.

@Test
public void customPesReader() throws Exception {
    CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false);
    TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory);
    FakeExtractorInput input = new FakeExtractorInput.Builder().setData(TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), "media/ts/sample_h262_mpeg_audio.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);
        if (readResult == Extractor.RESULT_SEEK) {
            input.setPosition((int) seekPositionHolder.position);
        }
    }
    CustomEsReader reader = factory.esReader;
    assertThat(reader.packetsRead).isEqualTo(2);
    TrackOutput trackOutput = reader.getTrackOutput();
    assertThat(trackOutput == output.trackOutputs.get(257)).isTrue();
    assertThat(((FakeTrackOutput) trackOutput).lastFormat).isEqualTo(new Format.Builder().setId("1/257").setSampleMimeType("mime").setLanguage("und").build());
}
Also used : FakeExtractorInput(androidx.media3.test.utils.FakeExtractorInput) FakeTrackOutput(androidx.media3.test.utils.FakeTrackOutput) TimestampAdjuster(androidx.media3.common.util.TimestampAdjuster) Format(androidx.media3.common.Format) PositionHolder(androidx.media3.extractor.PositionHolder) FakeExtractorOutput(androidx.media3.test.utils.FakeExtractorOutput) TrackOutput(androidx.media3.extractor.TrackOutput) FakeTrackOutput(androidx.media3.test.utils.FakeTrackOutput) Test(org.junit.Test)

Example 15 with TimestampAdjuster

use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.

the class TsExtractorTest method customInitialSectionReader.

@Test
public void customInitialSectionReader() throws Exception {
    CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true);
    TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory);
    FakeExtractorInput input = new FakeExtractorInput.Builder().setData(TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), "media/ts/sample_with_sdt.ts")).setSimulateIOErrors(false).setSimulateUnknownLength(false).setSimulatePartialReads(false).build();
    tsExtractor.init(new FakeExtractorOutput());
    PositionHolder seekPositionHolder = new PositionHolder();
    int readResult = Extractor.RESULT_CONTINUE;
    while (readResult != Extractor.RESULT_END_OF_INPUT) {
        readResult = tsExtractor.read(input, seekPositionHolder);
        if (readResult == Extractor.RESULT_SEEK) {
            input.setPosition((int) seekPositionHolder.position);
        }
    }
    assertThat(factory.sdtReader.consumedSdts).isEqualTo(2);
}
Also used : FakeExtractorInput(androidx.media3.test.utils.FakeExtractorInput) PositionHolder(androidx.media3.extractor.PositionHolder) TimestampAdjuster(androidx.media3.common.util.TimestampAdjuster) FakeExtractorOutput(androidx.media3.test.utils.FakeExtractorOutput) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)12 FakeExtractorInput (androidx.media3.test.utils.FakeExtractorInput)11 ExtractorInput (androidx.media3.extractor.ExtractorInput)9 TimestampAdjuster (androidx.media3.common.util.TimestampAdjuster)8 Nullable (androidx.annotation.Nullable)7 TrackOutput (androidx.media3.extractor.TrackOutput)4 FakeExtractorOutput (androidx.media3.test.utils.FakeExtractorOutput)4 Format (androidx.media3.common.Format)3 TsExtractor (androidx.media3.extractor.ts.TsExtractor)3 SuppressLint (android.annotation.SuppressLint)2 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)2 Extractor (androidx.media3.extractor.Extractor)2 PositionHolder (androidx.media3.extractor.PositionHolder)2 Mp3Extractor (androidx.media3.extractor.mp3.Mp3Extractor)2 FragmentedMp4Extractor (androidx.media3.extractor.mp4.FragmentedMp4Extractor)2 Ac3Extractor (androidx.media3.extractor.ts.Ac3Extractor)2 Ac4Extractor (androidx.media3.extractor.ts.Ac4Extractor)2 AdtsExtractor (androidx.media3.extractor.ts.AdtsExtractor)2 Before (org.junit.Before)2 Uri (android.net.Uri)1