Search in sources :

Example 96 with TrackOutput

use of androidx.media3.extractor.TrackOutput in project media by androidx.

the class FlacExtractorSeekTest method seeking_binarySearch_handlesSeekingBackward.

@Test
public void seeking_binarySearch_handlesSeekingBackward() throws IOException {
    String fileName = TEST_FILE_BINARY_SEARCH;
    Uri fileUri = TestUtil.buildAssetUri(fileName);
    SeekMap seekMap = TestUtil.extractSeekMap(extractor, extractorOutput, dataSource, fileUri);
    FakeTrackOutput trackOutput = extractorOutput.trackOutputs.get(0);
    long firstSeekTimeUs = 1_234_000;
    TestUtil.seekToTimeUs(extractor, seekMap, firstSeekTimeUs, dataSource, trackOutput, fileUri);
    long targetSeekTimeUs = 987_00;
    int extractedFrameIndex = TestUtil.seekToTimeUs(extractor, seekMap, targetSeekTimeUs, dataSource, trackOutput, fileUri);
    assertThat(extractedFrameIndex).isNotEqualTo(C.INDEX_UNSET);
    assertFirstFrameAfterSeekContainsTargetSeekTime(fileName, trackOutput, targetSeekTimeUs, extractedFrameIndex);
}
Also used : FakeTrackOutput(androidx.media3.test.utils.FakeTrackOutput) SeekMap(androidx.media3.extractor.SeekMap) Uri(android.net.Uri) Test(org.junit.Test)

Example 97 with TrackOutput

use of androidx.media3.extractor.TrackOutput in project media by androidx.

the class FlacExtractorSeekTest method seeking_binarySearch_handlesSeekToZero.

@Test
public void seeking_binarySearch_handlesSeekToZero() throws IOException {
    String fileName = TEST_FILE_BINARY_SEARCH;
    Uri fileUri = TestUtil.buildAssetUri(fileName);
    SeekMap seekMap = TestUtil.extractSeekMap(extractor, extractorOutput, dataSource, fileUri);
    FakeTrackOutput trackOutput = extractorOutput.trackOutputs.get(0);
    long targetSeekTimeUs = 0;
    int extractedFrameIndex = TestUtil.seekToTimeUs(extractor, seekMap, targetSeekTimeUs, dataSource, trackOutput, fileUri);
    assertThat(extractedFrameIndex).isNotEqualTo(C.INDEX_UNSET);
    assertFirstFrameAfterSeekContainsTargetSeekTime(fileName, trackOutput, targetSeekTimeUs, extractedFrameIndex);
}
Also used : FakeTrackOutput(androidx.media3.test.utils.FakeTrackOutput) SeekMap(androidx.media3.extractor.SeekMap) Uri(android.net.Uri) Test(org.junit.Test)

Example 98 with TrackOutput

use of androidx.media3.extractor.TrackOutput in project media by androidx.

the class JpegExtractor method outputImageTrack.

private void outputImageTrack(Metadata.Entry... metadataEntries) {
    TrackOutput imageTrackOutput = checkNotNull(extractorOutput).track(IMAGE_TRACK_ID, C.TRACK_TYPE_IMAGE);
    imageTrackOutput.format(new Format.Builder().setContainerMimeType(MimeTypes.IMAGE_JPEG).setMetadata(new Metadata(metadataEntries)).build());
}
Also used : Metadata(androidx.media3.common.Metadata) MotionPhotoMetadata(androidx.media3.extractor.metadata.mp4.MotionPhotoMetadata) TrackOutput(androidx.media3.extractor.TrackOutput)

Example 99 with TrackOutput

use of androidx.media3.extractor.TrackOutput in project media by androidx.

the class Mp4Extractor method processEndOfStreamReadingAtomHeader.

/**
 * Processes the end of stream in case there is not atom left to read.
 */
private void processEndOfStreamReadingAtomHeader() {
    if (fileType == FILE_TYPE_HEIC && (flags & FLAG_READ_MOTION_PHOTO_METADATA) != 0) {
        // Add image track and prepare media.
        ExtractorOutput extractorOutput = checkNotNull(this.extractorOutput);
        TrackOutput trackOutput = extractorOutput.track(/* id= */
        0, C.TRACK_TYPE_IMAGE);
        @Nullable Metadata metadata = motionPhotoMetadata == null ? null : new Metadata(motionPhotoMetadata);
        trackOutput.format(new Format.Builder().setMetadata(metadata).build());
        extractorOutput.endTracks();
        extractorOutput.seekMap(new SeekMap.Unseekable(/* durationUs= */
        C.TIME_UNSET));
    }
}
Also used : ExtractorOutput(androidx.media3.extractor.ExtractorOutput) Format(androidx.media3.common.Format) Metadata(androidx.media3.common.Metadata) MotionPhotoMetadata(androidx.media3.extractor.metadata.mp4.MotionPhotoMetadata) SeekMap(androidx.media3.extractor.SeekMap) TrackOutput(androidx.media3.extractor.TrackOutput) Nullable(androidx.annotation.Nullable)

Example 100 with TrackOutput

use of androidx.media3.extractor.TrackOutput in project media by androidx.

the class Mp4Extractor method readSample.

/**
 * Attempts to extract the next sample in the current mdat atom for the specified track.
 *
 * <p>Returns {@link #RESULT_SEEK} if the source should be reloaded from the position in {@code
 * positionHolder}.
 *
 * <p>Returns {@link #RESULT_END_OF_INPUT} if no samples are left. Otherwise, returns {@link
 * #RESULT_CONTINUE}.
 *
 * @param input The {@link ExtractorInput} from which to read data.
 * @param positionHolder If {@link #RESULT_SEEK} is returned, this holder is updated to hold the
 *     position of the required data.
 * @return One of the {@code RESULT_*} flags in {@link Extractor}.
 * @throws IOException If an error occurs reading from the input.
 */
private int readSample(ExtractorInput input, PositionHolder positionHolder) throws IOException {
    long inputPosition = input.getPosition();
    if (sampleTrackIndex == C.INDEX_UNSET) {
        sampleTrackIndex = getTrackIndexOfNextReadSample(inputPosition);
        if (sampleTrackIndex == C.INDEX_UNSET) {
            return RESULT_END_OF_INPUT;
        }
    }
    Mp4Track track = castNonNull(tracks)[sampleTrackIndex];
    TrackOutput trackOutput = track.trackOutput;
    int sampleIndex = track.sampleIndex;
    long position = track.sampleTable.offsets[sampleIndex];
    int sampleSize = track.sampleTable.sizes[sampleIndex];
    @Nullable TrueHdSampleRechunker trueHdSampleRechunker = track.trueHdSampleRechunker;
    long skipAmount = position - inputPosition + sampleBytesRead;
    if (skipAmount < 0 || skipAmount >= RELOAD_MINIMUM_SEEK_DISTANCE) {
        positionHolder.position = position;
        return RESULT_SEEK;
    }
    if (track.track.sampleTransformation == Track.TRANSFORMATION_CEA608_CDAT) {
        // The sample information is contained in a cdat atom. The header must be discarded for
        // committing.
        skipAmount += Atom.HEADER_SIZE;
        sampleSize -= Atom.HEADER_SIZE;
    }
    input.skipFully((int) skipAmount);
    if (track.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[] nalLengthData = nalLength.getData();
        nalLengthData[0] = 0;
        nalLengthData[1] = 0;
        nalLengthData[2] = 0;
        int nalUnitLengthFieldLength = track.track.nalUnitLengthFieldLength;
        int nalUnitLengthFieldLengthDiff = 4 - track.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.
                input.readFully(nalLengthData, nalUnitLengthFieldLengthDiff, nalUnitLengthFieldLength);
                sampleBytesRead += nalUnitLengthFieldLength;
                nalLength.setPosition(0);
                int nalLengthInt = nalLength.readInt();
                if (nalLengthInt < 0) {
                    throw ParserException.createForMalformedContainer("Invalid NAL length", /* cause= */
                    null);
                }
                sampleCurrentNalBytesRemaining = nalLengthInt;
                // Write a start code for the current NAL unit.
                nalStartCode.setPosition(0);
                trackOutput.sampleData(nalStartCode, 4);
                sampleBytesWritten += 4;
                sampleSize += nalUnitLengthFieldLengthDiff;
            } else {
                // Write the payload of the NAL unit.
                int writtenBytes = trackOutput.sampleData(input, sampleCurrentNalBytesRemaining, false);
                sampleBytesRead += writtenBytes;
                sampleBytesWritten += writtenBytes;
                sampleCurrentNalBytesRemaining -= writtenBytes;
            }
        }
    } else {
        if (MimeTypes.AUDIO_AC4.equals(track.track.format.sampleMimeType)) {
            if (sampleBytesWritten == 0) {
                Ac4Util.getAc4SampleHeader(sampleSize, scratch);
                trackOutput.sampleData(scratch, Ac4Util.SAMPLE_HEADER_SIZE);
                sampleBytesWritten += Ac4Util.SAMPLE_HEADER_SIZE;
            }
            sampleSize += Ac4Util.SAMPLE_HEADER_SIZE;
        } else if (trueHdSampleRechunker != null) {
            trueHdSampleRechunker.startSample(input);
        }
        while (sampleBytesWritten < sampleSize) {
            int writtenBytes = trackOutput.sampleData(input, sampleSize - sampleBytesWritten, false);
            sampleBytesRead += writtenBytes;
            sampleBytesWritten += writtenBytes;
            sampleCurrentNalBytesRemaining -= writtenBytes;
        }
    }
    long timeUs = track.sampleTable.timestampsUs[sampleIndex];
    @C.BufferFlags int flags = track.sampleTable.flags[sampleIndex];
    if (trueHdSampleRechunker != null) {
        trueHdSampleRechunker.sampleMetadata(trackOutput, timeUs, flags, sampleSize, /* offset= */
        0, /* cryptoData= */
        null);
        if (sampleIndex + 1 == track.sampleTable.sampleCount) {
            trueHdSampleRechunker.outputPendingSampleMetadata(trackOutput, /* cryptoData= */
            null);
        }
    } else {
        trackOutput.sampleMetadata(timeUs, flags, sampleSize, /* offset= */
        0, /* cryptoData= */
        null);
    }
    track.sampleIndex++;
    sampleTrackIndex = C.INDEX_UNSET;
    sampleBytesRead = 0;
    sampleBytesWritten = 0;
    sampleCurrentNalBytesRemaining = 0;
    return RESULT_CONTINUE;
}
Also used : TrueHdSampleRechunker(androidx.media3.extractor.TrueHdSampleRechunker) TrackOutput(androidx.media3.extractor.TrackOutput) SeekPoint(androidx.media3.extractor.SeekPoint) Nullable(androidx.annotation.Nullable)

Aggregations

FakeTrackOutput (androidx.media3.test.utils.FakeTrackOutput)70 Test (org.junit.Test)61 SeekMap (androidx.media3.extractor.SeekMap)60 Uri (android.net.Uri)50 TrackOutput (com.google.android.exoplayer2.extractor.TrackOutput)38 FakeExtractorOutput (androidx.media3.test.utils.FakeExtractorOutput)31 TrackOutput (androidx.media3.extractor.TrackOutput)19 Nullable (androidx.annotation.Nullable)13 Format (androidx.media3.common.Format)11 RequiresNonNull (org.checkerframework.checker.nullness.qual.RequiresNonNull)11 Format (com.google.android.exoplayer2.Format)8 FakeExtractorInput (androidx.media3.test.utils.FakeExtractorInput)5 ParserException (com.google.android.exoplayer2.ParserException)5 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)5 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)4 SeekPoint (androidx.media3.extractor.SeekPoint)4 Metadata (androidx.media3.common.Metadata)3 Cue (androidx.media3.common.text.Cue)3 DefaultExtractorInput (androidx.media3.extractor.DefaultExtractorInput)3 ExtractorInput (androidx.media3.extractor.ExtractorInput)3