Search in sources :

Example 31 with Segment

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;
        }
    }
}
Also used : FakeData(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData) IOException(java.io.IOException) Segment(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)

Example 32 with Segment

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);
}
Also used : ParserException(com.google.android.exoplayer2.ParserException) ArrayList(java.util.ArrayList) Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)

Example 33 with Segment

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;
}
Also used : Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)

Example 34 with Segment

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;
    }
}
Also used : DataSourceException(com.google.android.exoplayer2.upstream.DataSourceException) FakeData(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData) IOException(java.io.IOException) Segment(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)

Example 35 with Segment

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();
}
Also used : Segment(com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)

Aggregations

Test (org.junit.Test)20 Uri (android.net.Uri)18 Segment (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)18 Nullable (androidx.annotation.Nullable)16 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)11 ByteArrayInputStream (java.io.ByteArrayInputStream)9 IOException (java.io.IOException)9 InputStream (java.io.InputStream)9 ArrayList (java.util.ArrayList)9 HlsMediaPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist)8 Format (com.google.android.exoplayer2.Format)6 SlowMotionData (com.google.android.exoplayer2.metadata.mp4.SlowMotionData)5 SingleSampleMediaChunk (com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk)5 RangedUri (com.google.android.exoplayer2.source.dash.manifest.RangedUri)5 Representation (com.google.android.exoplayer2.source.dash.manifest.Representation)5 BehindLiveWindowException (com.google.android.exoplayer2.source.BehindLiveWindowException)4 ContainerMediaChunk (com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)4 Segment (com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)4 Window (com.google.android.exoplayer2.Timeline.Window)3 Segment (com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment)3