use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.
the class FakeDataSource method read.
@Override
public final int read(byte[] buffer, int offset, int length) throws IOException {
Assertions.checkState(sourceOpened);
while (true) {
FakeData fakeData = Util.castNonNull(this.fakeData);
if (currentSegmentIndex == fakeData.getSegments().size() || bytesRemaining == 0) {
return C.RESULT_END_OF_INPUT;
}
Segment current = fakeData.getSegments().get(currentSegmentIndex);
if (current.isErrorSegment()) {
if (!current.exceptionCleared) {
current.exceptionThrown = true;
throw (IOException) Util.castNonNull(current.exception).fillInStackTrace();
} else {
currentSegmentIndex++;
}
} else if (current.isActionSegment()) {
currentSegmentIndex++;
Util.castNonNull(current.action).run();
} else {
// Read at most bytesRemaining.
length = (int) min(length, bytesRemaining);
// Do not allow crossing of the segment boundary.
length = min(length, current.length - current.bytesRead);
// Perform the read and return.
Assertions.checkArgument(buffer.length - offset >= length);
if (current.data != null) {
System.arraycopy(current.data, current.bytesRead, buffer, offset, length);
}
onDataRead(length);
bytesTransferred(length);
bytesRemaining -= length;
current.bytesRead += length;
if (current.bytesRead == current.length) {
currentSegmentIndex++;
}
return length;
}
}
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.
the class HlsPlaylistParser method parseMediaPlaylist.
private static HlsMediaPlaylist parseMediaPlaylist(LineIterator iterator, String baseUri) throws IOException {
@HlsMediaPlaylist.PlaylistType int playlistType = HlsMediaPlaylist.PLAYLIST_TYPE_UNKNOWN;
long startOffsetUs = C.TIME_UNSET;
int mediaSequence = 0;
// Default version == 1.
int version = 1;
long targetDurationUs = C.TIME_UNSET;
boolean hasEndTag = false;
Segment initializationSegment = null;
List<Segment> segments = new ArrayList<>();
long segmentDurationUs = 0;
boolean hasDiscontinuitySequence = false;
int playlistDiscontinuitySequence = 0;
int relativeDiscontinuitySequence = 0;
long playlistStartTimeUs = 0;
long segmentStartTimeUs = 0;
long segmentByteRangeOffset = 0;
long segmentByteRangeLength = C.LENGTH_UNSET;
int segmentMediaSequence = 0;
boolean isEncrypted = false;
String encryptionKeyUri = null;
String encryptionIV = null;
String line;
while (iterator.hasNext()) {
line = iterator.next();
if (line.startsWith(TAG_PLAYLIST_TYPE)) {
String playlistTypeString = parseStringAttr(line, REGEX_PLAYLIST_TYPE);
if ("VOD".equals(playlistTypeString)) {
playlistType = HlsMediaPlaylist.PLAYLIST_TYPE_VOD;
} else if ("EVENT".equals(playlistTypeString)) {
playlistType = HlsMediaPlaylist.PLAYLIST_TYPE_EVENT;
} else {
throw new ParserException("Illegal playlist type: " + playlistTypeString);
}
} else if (line.startsWith(TAG_START)) {
startOffsetUs = (long) (parseDoubleAttr(line, REGEX_TIME_OFFSET) * C.MICROS_PER_SECOND);
} else if (line.startsWith(TAG_INIT_SEGMENT)) {
String uri = parseStringAttr(line, REGEX_URI);
String byteRange = parseOptionalStringAttr(line, REGEX_ATTR_BYTERANGE);
if (byteRange != null) {
String[] splitByteRange = byteRange.split("@");
segmentByteRangeLength = Long.parseLong(splitByteRange[0]);
if (splitByteRange.length > 1) {
segmentByteRangeOffset = Long.parseLong(splitByteRange[1]);
}
}
initializationSegment = new Segment(uri, segmentByteRangeOffset, segmentByteRangeLength);
segmentByteRangeOffset = 0;
segmentByteRangeLength = C.LENGTH_UNSET;
} else if (line.startsWith(TAG_TARGET_DURATION)) {
targetDurationUs = parseIntAttr(line, REGEX_TARGET_DURATION) * C.MICROS_PER_SECOND;
} else if (line.startsWith(TAG_MEDIA_SEQUENCE)) {
mediaSequence = parseIntAttr(line, REGEX_MEDIA_SEQUENCE);
segmentMediaSequence = mediaSequence;
} else if (line.startsWith(TAG_VERSION)) {
version = parseIntAttr(line, REGEX_VERSION);
} else if (line.startsWith(TAG_MEDIA_DURATION)) {
segmentDurationUs = (long) (parseDoubleAttr(line, REGEX_MEDIA_DURATION) * C.MICROS_PER_SECOND);
} else if (line.startsWith(TAG_KEY)) {
String method = parseStringAttr(line, REGEX_METHOD);
isEncrypted = METHOD_AES128.equals(method);
if (isEncrypted) {
encryptionKeyUri = parseStringAttr(line, REGEX_URI);
encryptionIV = parseOptionalStringAttr(line, REGEX_IV);
} else {
encryptionKeyUri = null;
encryptionIV = null;
}
} else if (line.startsWith(TAG_BYTERANGE)) {
String byteRange = parseStringAttr(line, REGEX_BYTERANGE);
String[] splitByteRange = byteRange.split("@");
segmentByteRangeLength = Long.parseLong(splitByteRange[0]);
if (splitByteRange.length > 1) {
segmentByteRangeOffset = Long.parseLong(splitByteRange[1]);
}
} else if (line.startsWith(TAG_DISCONTINUITY_SEQUENCE)) {
hasDiscontinuitySequence = true;
playlistDiscontinuitySequence = Integer.parseInt(line.substring(line.indexOf(':') + 1));
} else if (line.equals(TAG_DISCONTINUITY)) {
relativeDiscontinuitySequence++;
} else if (line.startsWith(TAG_PROGRAM_DATE_TIME)) {
if (playlistStartTimeUs == 0) {
long programDatetimeUs = C.msToUs(Util.parseXsDateTime(line.substring(line.indexOf(':') + 1)));
playlistStartTimeUs = programDatetimeUs - segmentStartTimeUs;
}
} else if (!line.startsWith("#")) {
String segmentEncryptionIV;
if (!isEncrypted) {
segmentEncryptionIV = null;
} else if (encryptionIV != null) {
segmentEncryptionIV = encryptionIV;
} else {
segmentEncryptionIV = Integer.toHexString(segmentMediaSequence);
}
segmentMediaSequence++;
if (segmentByteRangeLength == C.LENGTH_UNSET) {
segmentByteRangeOffset = 0;
}
segments.add(new Segment(line, segmentDurationUs, relativeDiscontinuitySequence, segmentStartTimeUs, isEncrypted, encryptionKeyUri, segmentEncryptionIV, segmentByteRangeOffset, segmentByteRangeLength));
segmentStartTimeUs += segmentDurationUs;
segmentDurationUs = 0;
if (segmentByteRangeLength != C.LENGTH_UNSET) {
segmentByteRangeOffset += segmentByteRangeLength;
}
segmentByteRangeLength = C.LENGTH_UNSET;
} else if (line.equals(TAG_ENDLIST)) {
hasEndTag = true;
}
}
return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, playlistStartTimeUs, hasDiscontinuitySequence, playlistDiscontinuitySequence, mediaSequence, version, targetDurationUs, hasEndTag, playlistStartTimeUs != 0, initializationSegment, segments);
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.
the class HlsPlaylistTracker method getLoadedPlaylistDiscontinuitySequence.
private int getLoadedPlaylistDiscontinuitySequence(HlsMediaPlaylist oldPlaylist, HlsMediaPlaylist loadedPlaylist) {
if (loadedPlaylist.hasDiscontinuitySequence) {
return loadedPlaylist.discontinuitySequence;
}
// TODO: Improve cross-playlist discontinuity adjustment.
int primaryUrlDiscontinuitySequence = primaryUrlSnapshot != null ? primaryUrlSnapshot.discontinuitySequence : 0;
if (oldPlaylist == null) {
return primaryUrlDiscontinuitySequence;
}
Segment firstOldOverlappingSegment = getFirstOldOverlappingSegment(oldPlaylist, loadedPlaylist);
if (firstOldOverlappingSegment != null) {
return oldPlaylist.discontinuitySequence + firstOldOverlappingSegment.relativeDiscontinuitySequence - loadedPlaylist.segments.get(0).relativeDiscontinuitySequence;
}
return primaryUrlDiscontinuitySequence;
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.
the class FakeDataSource method open.
@Override
public final long open(DataSpec dataSpec) throws IOException {
Assertions.checkState(!openCalled);
openCalled = true;
// DataSpec requires a matching close call even if open fails.
uri = dataSpec.uri;
openedDataSpecs.add(dataSpec);
transferInitializing(dataSpec);
FakeData fakeData = fakeDataSet.getData(dataSpec.uri.toString());
if (fakeData == null) {
throw new IOException("Data not found: " + dataSpec.uri);
}
this.fakeData = fakeData;
long totalLength = 0;
for (Segment segment : fakeData.getSegments()) {
totalLength += segment.length;
}
if (totalLength == 0) {
throw new IOException("Data is empty: " + dataSpec.uri);
}
if (dataSpec.position > totalLength) {
throw new DataSourceException(PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE);
}
// Scan through the segments, configuring them for the current read.
boolean findingCurrentSegmentIndex = true;
currentSegmentIndex = 0;
int scannedLength = 0;
for (Segment segment : fakeData.getSegments()) {
segment.bytesRead = (int) min(max(0, dataSpec.position - scannedLength), segment.length);
scannedLength += segment.length;
findingCurrentSegmentIndex &= segment.isErrorSegment() ? segment.exceptionCleared : (!segment.isActionSegment() && segment.bytesRead == segment.length);
if (findingCurrentSegmentIndex) {
currentSegmentIndex++;
}
}
sourceOpened = true;
transferStarted(dataSpec);
// Configure bytesRemaining, and return.
if (dataSpec.length == C.LENGTH_UNSET) {
bytesRemaining = totalLength - dataSpec.position;
return fakeData.isSimulatingUnknownLength() ? C.LENGTH_UNSET : bytesRemaining;
} else {
bytesRemaining = dataSpec.length;
return bytesRemaining;
}
}
use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.
the class FakeDataSource method close.
@Override
public final void close() {
Assertions.checkState(openCalled);
openCalled = false;
uri = null;
if (fakeData != null && currentSegmentIndex < fakeData.getSegments().size()) {
Segment current = fakeData.getSegments().get(currentSegmentIndex);
if (current.isErrorSegment() && current.exceptionThrown) {
current.exceptionCleared = true;
}
}
if (sourceOpened) {
sourceOpened = false;
transferEnded();
}
fakeData = null;
onClosed();
}
Aggregations