Search in sources :

Example 11 with ParserException

use of androidx.media3.common.ParserException in project media by androidx.

the class HlsMediaSourceTest method loadLivePlaylist_targetLiveOffsetLargerThanLiveWindow_targetLiveOffsetIsWithinLiveWindow.

@Test
public void loadLivePlaylist_targetLiveOffsetLargerThanLiveWindow_targetLiveOffsetIsWithinLiveWindow() throws TimeoutException, ParserException {
    String playlistUri = "fake://foo.bar/media0/playlist.m3u8";
    // The playlist has a duration of 8 seconds and a hold back of 12 seconds.
    String playlist = "#EXTM3U\n" + "#EXT-X-PROGRAM-DATE-TIME:2020-01-01T00:00:00.0+00:00\n" + "#EXT-X-TARGETDURATION:4\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-MEDIA-SEQUENCE:0\n" + "#EXTINF:4.00000,\n" + "fileSequence0.ts\n" + "#EXTINF:4.00000,\n" + "fileSequence1.ts\n" + "#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24";
    // The playlist finishes 1 second before the live edge, therefore the live window duration is
    // 9 seconds (8 + 1).
    SystemClock.setCurrentTimeMillis(Util.parseXsDateTime("2020-01-01T00:00:09.0+00:00"));
    HlsMediaSource.Factory factory = createHlsMediaSourceFactory(playlistUri, playlist);
    MediaItem mediaItem = new MediaItem.Builder().setUri(playlistUri).setLiveConfiguration(new MediaItem.LiveConfiguration.Builder().setTargetOffsetMs(20_000).build()).build();
    HlsMediaSource mediaSource = factory.createMediaSource(mediaItem);
    Timeline timeline = prepareAndWaitForTimeline(mediaSource);
    Timeline.Window window = timeline.getWindow(0, new Timeline.Window());
    assertThat(mediaItem.liveConfiguration.targetOffsetMs).isGreaterThan(Util.usToMs(window.durationUs));
    assertThat(window.liveConfiguration.targetOffsetMs).isEqualTo(9000);
}
Also used : Timeline(androidx.media3.common.Timeline) MediaItem(androidx.media3.common.MediaItem) Test(org.junit.Test)

Example 12 with ParserException

use of androidx.media3.common.ParserException in project media by androidx.

the class RtspTrackTiming method parseTrackTiming.

/**
 * Parses the RTP-Info header into a list of {@link RtspTrackTiming RtspTrackTimings}.
 *
 * <p>The syntax of the RTP-Info (RFC2326 Section 12.33):
 *
 * <pre>
 *   RTP-Info        = "RTP-Info" ":" 1#stream-url 1*parameter
 *   stream-url      = "url" "=" url
 *   parameter       = ";" "seq" "=" 1*DIGIT
 *                   | ";" "rtptime" "=" 1*DIGIT
 * </pre>
 *
 * <p>Examples from RFC2326:
 *
 * <pre>
 *   RTP-Info:url=rtsp://foo.com/bar.file; seq=232433;rtptime=972948234
 *   RTP-Info:url=rtsp://foo.com/bar.avi/streamid=0;seq=45102,
 *            url=rtsp://foo.com/bar.avi/streamid=1;seq=30211
 * </pre>
 *
 * @param rtpInfoString The value of the RTP-Info header, with header name (RTP-Info) removed.
 * @param sessionUri The session URI, must include an {@code rtsp} scheme.
 * @return A list of parsed {@link RtspTrackTiming}.
 * @throws ParserException If parsing failed.
 */
public static ImmutableList<RtspTrackTiming> parseTrackTiming(String rtpInfoString, Uri sessionUri) throws ParserException {
    ImmutableList.Builder<RtspTrackTiming> listBuilder = new ImmutableList.Builder<>();
    for (String perTrackTimingString : Util.split(rtpInfoString, ",")) {
        long rtpTime = C.TIME_UNSET;
        int sequenceNumber = C.INDEX_UNSET;
        @Nullable Uri uri = null;
        for (String attributePair : Util.split(perTrackTimingString, ";")) {
            try {
                String[] attributes = Util.splitAtFirst(attributePair, "=");
                String attributeName = attributes[0];
                String attributeValue = attributes[1];
                switch(attributeName) {
                    case "url":
                        uri = resolveUri(/* urlString= */
                        attributeValue, sessionUri);
                        break;
                    case "seq":
                        sequenceNumber = Integer.parseInt(attributeValue);
                        break;
                    case "rtptime":
                        rtpTime = Long.parseLong(attributeValue);
                        break;
                    default:
                        throw ParserException.createForMalformedManifest(attributeName, /* cause= */
                        null);
                }
            } catch (Exception e) {
                throw ParserException.createForMalformedManifest(attributePair, e);
            }
        }
        if (uri == null || // Checks if the URI is a URL.
        uri.getScheme() == null || (sequenceNumber == C.INDEX_UNSET && rtpTime == C.TIME_UNSET)) {
            throw ParserException.createForMalformedManifest(perTrackTimingString, /* cause= */
            null);
        }
        listBuilder.add(new RtspTrackTiming(rtpTime, sequenceNumber, uri));
    }
    return listBuilder.build();
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) Uri(android.net.Uri) Nullable(androidx.annotation.Nullable) ParserException(androidx.media3.common.ParserException)

Example 13 with ParserException

use of androidx.media3.common.ParserException in project media by androidx.

the class FlacMetadataReader method readStreamMarker.

/**
 * Reads the FLAC stream marker.
 *
 * @param input Input stream to read the stream marker from.
 * @throws ParserException If an error occurs parsing the stream marker. In this case, the
 *     position of {@code input} is advanced by {@link FlacConstants#STREAM_MARKER_SIZE} bytes.
 * @throws IOException If reading from the input fails. In this case, the position is left
 *     unchanged.
 */
public static void readStreamMarker(ExtractorInput input) throws IOException {
    ParsableByteArray scratch = new ParsableByteArray(FlacConstants.STREAM_MARKER_SIZE);
    input.readFully(scratch.getData(), 0, FlacConstants.STREAM_MARKER_SIZE);
    if (scratch.readUnsignedInt() != STREAM_MARKER) {
        throw ParserException.createForMalformedContainer("Failed to read FLAC stream marker.", /* cause= */
        null);
    }
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray)

Example 14 with ParserException

use of androidx.media3.common.ParserException in project media by androidx.

the class AudioTagPayloadReader method parsePayload.

@Override
protected boolean parsePayload(ParsableByteArray data, long timeUs) throws ParserException {
    if (audioFormat == AUDIO_FORMAT_MP3) {
        int sampleSize = data.bytesLeft();
        output.sampleData(data, sampleSize);
        output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
        return true;
    } else {
        int packetType = data.readUnsignedByte();
        if (packetType == AAC_PACKET_TYPE_SEQUENCE_HEADER && !hasOutputFormat) {
            // Parse the sequence header.
            byte[] audioSpecificConfig = new byte[data.bytesLeft()];
            data.readBytes(audioSpecificConfig, 0, audioSpecificConfig.length);
            AacUtil.Config aacConfig = AacUtil.parseAudioSpecificConfig(audioSpecificConfig);
            Format format = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setCodecs(aacConfig.codecs).setChannelCount(aacConfig.channelCount).setSampleRate(aacConfig.sampleRateHz).setInitializationData(Collections.singletonList(audioSpecificConfig)).build();
            output.format(format);
            hasOutputFormat = true;
            return false;
        } else if (audioFormat != AUDIO_FORMAT_AAC || packetType == AAC_PACKET_TYPE_AAC_RAW) {
            int sampleSize = data.bytesLeft();
            output.sampleData(data, sampleSize);
            output.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0, null);
            return true;
        } else {
            return false;
        }
    }
}
Also used : AacUtil(androidx.media3.extractor.AacUtil) Format(androidx.media3.common.Format)

Example 15 with ParserException

use of androidx.media3.common.ParserException in project media by androidx.

the class FragmentedMp4Extractor method parseSidx.

/**
 * Parses a sidx atom (defined in 14496-12).
 *
 * @param atom The atom data.
 * @param inputPosition The input position of the first byte after the atom.
 * @return A pair consisting of the earliest presentation time in microseconds, and the parsed
 *     {@link ChunkIndex}.
 */
private static Pair<Long, ChunkIndex> parseSidx(ParsableByteArray atom, long inputPosition) throws ParserException {
    atom.setPosition(Atom.HEADER_SIZE);
    int fullAtom = atom.readInt();
    int version = Atom.parseFullAtomVersion(fullAtom);
    atom.skipBytes(4);
    long timescale = atom.readUnsignedInt();
    long earliestPresentationTime;
    long offset = inputPosition;
    if (version == 0) {
        earliestPresentationTime = atom.readUnsignedInt();
        offset += atom.readUnsignedInt();
    } else {
        earliestPresentationTime = atom.readUnsignedLongToLong();
        offset += atom.readUnsignedLongToLong();
    }
    long earliestPresentationTimeUs = Util.scaleLargeTimestamp(earliestPresentationTime, C.MICROS_PER_SECOND, timescale);
    atom.skipBytes(2);
    int referenceCount = atom.readUnsignedShort();
    int[] sizes = new int[referenceCount];
    long[] offsets = new long[referenceCount];
    long[] durationsUs = new long[referenceCount];
    long[] timesUs = new long[referenceCount];
    long time = earliestPresentationTime;
    long timeUs = earliestPresentationTimeUs;
    for (int i = 0; i < referenceCount; i++) {
        int firstInt = atom.readInt();
        int type = 0x80000000 & firstInt;
        if (type != 0) {
            throw ParserException.createForMalformedContainer("Unhandled indirect reference", /* cause= */
            null);
        }
        long referenceDuration = atom.readUnsignedInt();
        sizes[i] = 0x7FFFFFFF & firstInt;
        offsets[i] = offset;
        // Calculate time and duration values such that any rounding errors are consistent. i.e. That
        // timesUs[i] + durationsUs[i] == timesUs[i + 1].
        timesUs[i] = timeUs;
        time += referenceDuration;
        timeUs = Util.scaleLargeTimestamp(time, C.MICROS_PER_SECOND, timescale);
        durationsUs[i] = timeUs - timesUs[i];
        atom.skipBytes(4);
        offset += sizes[i];
    }
    return Pair.create(earliestPresentationTimeUs, new ChunkIndex(sizes, offsets, durationsUs, timesUs));
}
Also used : ChunkIndex(androidx.media3.extractor.ChunkIndex)

Aggregations

Test (org.junit.Test)25 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)15 MediaItem (androidx.media3.common.MediaItem)13 Timeline (androidx.media3.common.Timeline)13 Nullable (androidx.annotation.Nullable)12 ParserException (androidx.media3.common.ParserException)11 Format (androidx.media3.common.Format)6 PositionHolder (androidx.media3.extractor.PositionHolder)5 FakeExtractorInput (androidx.media3.test.utils.FakeExtractorInput)5 LeafAtom (androidx.media3.extractor.mp4.Atom.LeafAtom)4 DrmInitData (androidx.media3.common.DrmInitData)3 ContainerAtom (androidx.media3.extractor.mp4.Atom.ContainerAtom)3 RequiresNonNull (org.checkerframework.checker.nullness.qual.RequiresNonNull)3 Uri (android.net.Uri)2 CallSuper (androidx.annotation.CallSuper)2 SchemeData (androidx.media3.common.DrmInitData.SchemeData)2 AacUtil (androidx.media3.extractor.AacUtil)2 AvcConfig (androidx.media3.extractor.AvcConfig)2 GaplessInfoHolder (androidx.media3.extractor.GaplessInfoHolder)2 ArrayList (java.util.ArrayList)2