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);
}
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();
}
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);
}
}
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;
}
}
}
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));
}
Aggregations