Add support for HLS's #EXT-X-PLAYLIST-TYPE
Issue:#805 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=145991145
This commit is contained in:
parent
7ee8567f4a
commit
e6bbd397d5
@ -35,6 +35,7 @@ public class HlsMediaPlaylistParserTest extends TestCase {
|
|||||||
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
||||||
String playlistString = "#EXTM3U\n"
|
String playlistString = "#EXTM3U\n"
|
||||||
+ "#EXT-X-VERSION:3\n"
|
+ "#EXT-X-VERSION:3\n"
|
||||||
|
+ "#EXT-X-PLAYLIST-TYPE:VOD\n"
|
||||||
+ "#EXT-X-TARGETDURATION:8\n"
|
+ "#EXT-X-TARGETDURATION:8\n"
|
||||||
+ "#EXT-X-MEDIA-SEQUENCE:2679\n"
|
+ "#EXT-X-MEDIA-SEQUENCE:2679\n"
|
||||||
+ "#EXT-X-DISCONTINUITY-SEQUENCE:4\n"
|
+ "#EXT-X-DISCONTINUITY-SEQUENCE:4\n"
|
||||||
@ -71,6 +72,7 @@ public class HlsMediaPlaylistParserTest extends TestCase {
|
|||||||
assertEquals(HlsPlaylist.TYPE_MEDIA, playlist.type);
|
assertEquals(HlsPlaylist.TYPE_MEDIA, playlist.type);
|
||||||
|
|
||||||
HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
|
HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
|
||||||
|
assertEquals(HlsMediaPlaylist.PLAYLIST_TYPE_VOD, mediaPlaylist.playlistType);
|
||||||
|
|
||||||
assertEquals(2679, mediaPlaylist.mediaSequence);
|
assertEquals(2679, mediaPlaylist.mediaSequence);
|
||||||
assertEquals(3, mediaPlaylist.version);
|
assertEquals(3, mediaPlaylist.version);
|
||||||
|
@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.source.hls.playlist;
|
package com.google.android.exoplayer2.source.hls.playlist;
|
||||||
|
|
||||||
|
import android.support.annotation.IntDef;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -65,6 +68,18 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the playlist as specified by #EXT-X-PLAYLIST-TYPE.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({PLAYLIST_TYPE_UNKNOWN, PLAYLIST_TYPE_VOD, PLAYLIST_TYPE_EVENT})
|
||||||
|
public @interface PlaylistType {}
|
||||||
|
public static final int PLAYLIST_TYPE_UNKNOWN = 0;
|
||||||
|
public static final int PLAYLIST_TYPE_VOD = 1;
|
||||||
|
public static final int PLAYLIST_TYPE_EVENT = 2;
|
||||||
|
|
||||||
|
@PlaylistType
|
||||||
|
public final int playlistType;
|
||||||
public final long startOffsetUs;
|
public final long startOffsetUs;
|
||||||
public final long startTimeUs;
|
public final long startTimeUs;
|
||||||
public final boolean hasDiscontinuitySequence;
|
public final boolean hasDiscontinuitySequence;
|
||||||
@ -78,11 +93,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
public final List<Segment> segments;
|
public final List<Segment> segments;
|
||||||
public final long durationUs;
|
public final long durationUs;
|
||||||
|
|
||||||
public HlsMediaPlaylist(String baseUri, long startOffsetUs, long startTimeUs,
|
public HlsMediaPlaylist(@PlaylistType int playlistType, String baseUri, long startOffsetUs,
|
||||||
boolean hasDiscontinuitySequence, int discontinuitySequence, int mediaSequence, int version,
|
long startTimeUs, boolean hasDiscontinuitySequence, int discontinuitySequence,
|
||||||
long targetDurationUs, boolean hasEndTag, boolean hasProgramDateTime,
|
int mediaSequence, int version, long targetDurationUs, boolean hasEndTag,
|
||||||
Segment initializationSegment, List<Segment> segments) {
|
boolean hasProgramDateTime, Segment initializationSegment, List<Segment> segments) {
|
||||||
super(baseUri, HlsPlaylist.TYPE_MEDIA);
|
super(baseUri, HlsPlaylist.TYPE_MEDIA);
|
||||||
|
this.playlistType = playlistType;
|
||||||
this.startTimeUs = startTimeUs;
|
this.startTimeUs = startTimeUs;
|
||||||
this.hasDiscontinuitySequence = hasDiscontinuitySequence;
|
this.hasDiscontinuitySequence = hasDiscontinuitySequence;
|
||||||
this.discontinuitySequence = discontinuitySequence;
|
this.discontinuitySequence = discontinuitySequence;
|
||||||
@ -137,9 +153,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
* @return The playlist.
|
* @return The playlist.
|
||||||
*/
|
*/
|
||||||
public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) {
|
public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) {
|
||||||
return new HlsMediaPlaylist(baseUri, startOffsetUs, startTimeUs, true, discontinuitySequence,
|
return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs, true,
|
||||||
mediaSequence, version, targetDurationUs, hasEndTag, hasProgramDateTime,
|
discontinuitySequence, mediaSequence, version, targetDurationUs, hasEndTag,
|
||||||
initializationSegment, segments);
|
hasProgramDateTime, initializationSegment, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,9 +168,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
if (this.hasEndTag) {
|
if (this.hasEndTag) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return new HlsMediaPlaylist(baseUri, startOffsetUs, startTimeUs, hasDiscontinuitySequence,
|
return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, startTimeUs,
|
||||||
discontinuitySequence, mediaSequence, version, targetDurationUs, true, hasProgramDateTime,
|
hasDiscontinuitySequence, discontinuitySequence, mediaSequence, version, targetDurationUs,
|
||||||
initializationSegment, segments);
|
true, hasProgramDateTime, initializationSegment, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
private static final String PLAYLIST_HEADER = "#EXTM3U";
|
private static final String PLAYLIST_HEADER = "#EXTM3U";
|
||||||
|
|
||||||
private static final String TAG_VERSION = "#EXT-X-VERSION";
|
private static final String TAG_VERSION = "#EXT-X-VERSION";
|
||||||
|
private static final String TAG_PLAYLIST_TYPE = "#EXT-X-PLAYLIST-TYPE";
|
||||||
private static final String TAG_STREAM_INF = "#EXT-X-STREAM-INF";
|
private static final String TAG_STREAM_INF = "#EXT-X-STREAM-INF";
|
||||||
private static final String TAG_MEDIA = "#EXT-X-MEDIA";
|
private static final String TAG_MEDIA = "#EXT-X-MEDIA";
|
||||||
private static final String TAG_TARGET_DURATION = "#EXT-X-TARGETDURATION";
|
private static final String TAG_TARGET_DURATION = "#EXT-X-TARGETDURATION";
|
||||||
@ -74,6 +75,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
private static final Pattern REGEX_TARGET_DURATION = Pattern.compile(TAG_TARGET_DURATION
|
private static final Pattern REGEX_TARGET_DURATION = Pattern.compile(TAG_TARGET_DURATION
|
||||||
+ ":(\\d+)\\b");
|
+ ":(\\d+)\\b");
|
||||||
private static final Pattern REGEX_VERSION = Pattern.compile(TAG_VERSION + ":(\\d+)\\b");
|
private static final Pattern REGEX_VERSION = Pattern.compile(TAG_VERSION + ":(\\d+)\\b");
|
||||||
|
private static final Pattern REGEX_PLAYLIST_TYPE = Pattern.compile(TAG_PLAYLIST_TYPE
|
||||||
|
+ ":(.+)\\b");
|
||||||
private static final Pattern REGEX_MEDIA_SEQUENCE = Pattern.compile(TAG_MEDIA_SEQUENCE
|
private static final Pattern REGEX_MEDIA_SEQUENCE = Pattern.compile(TAG_MEDIA_SEQUENCE
|
||||||
+ ":(\\d+)\\b");
|
+ ":(\\d+)\\b");
|
||||||
private static final Pattern REGEX_MEDIA_DURATION = Pattern.compile(TAG_MEDIA_DURATION
|
private static final Pattern REGEX_MEDIA_DURATION = Pattern.compile(TAG_MEDIA_DURATION
|
||||||
@ -245,6 +248,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
|
|
||||||
private static HlsMediaPlaylist parseMediaPlaylist(LineIterator iterator, String baseUri)
|
private static HlsMediaPlaylist parseMediaPlaylist(LineIterator iterator, String baseUri)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@HlsMediaPlaylist.PlaylistType int playlistType = HlsMediaPlaylist.PLAYLIST_TYPE_UNKNOWN;
|
||||||
long startOffsetUs = C.TIME_UNSET;
|
long startOffsetUs = C.TIME_UNSET;
|
||||||
int mediaSequence = 0;
|
int mediaSequence = 0;
|
||||||
int version = 1; // Default version == 1.
|
int version = 1; // Default version == 1.
|
||||||
@ -270,7 +274,16 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
String line;
|
String line;
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
line = iterator.next();
|
line = iterator.next();
|
||||||
if (line.startsWith(TAG_START)) {
|
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);
|
startOffsetUs = (long) (parseDoubleAttr(line, REGEX_TIME_OFFSET) * C.MICROS_PER_SECOND);
|
||||||
} else if (line.startsWith(TAG_INIT_SEGMENT)) {
|
} else if (line.startsWith(TAG_INIT_SEGMENT)) {
|
||||||
String uri = parseStringAttr(line, REGEX_URI);
|
String uri = parseStringAttr(line, REGEX_URI);
|
||||||
@ -349,7 +362,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
hasEndTag = true;
|
hasEndTag = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new HlsMediaPlaylist(baseUri, startOffsetUs, playlistStartTimeUs,
|
return new HlsMediaPlaylist(playlistType, baseUri, startOffsetUs, playlistStartTimeUs,
|
||||||
hasDiscontinuitySequence, playlistDiscontinuitySequence, mediaSequence, version,
|
hasDiscontinuitySequence, playlistDiscontinuitySequence, mediaSequence, version,
|
||||||
targetDurationUs, hasEndTag, playlistStartTimeUs != 0, initializationSegment, segments);
|
targetDurationUs, hasEndTag, playlistStartTimeUs != 0, initializationSegment, segments);
|
||||||
}
|
}
|
||||||
|
@ -450,10 +450,11 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
|||||||
if (playlistSnapshot == null) {
|
if (playlistSnapshot == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO: Return true for event playlists once playlist types are supported.
|
|
||||||
long currentTimeMs = SystemClock.elapsedRealtime();
|
long currentTimeMs = SystemClock.elapsedRealtime();
|
||||||
long snapshotValidityDurationMs = Math.max(30000, C.usToMs(playlistSnapshot.durationUs));
|
long snapshotValidityDurationMs = Math.max(30000, C.usToMs(playlistSnapshot.durationUs));
|
||||||
return playlistSnapshot.hasEndTag
|
return playlistSnapshot.hasEndTag
|
||||||
|
|| playlistSnapshot.playlistType == HlsMediaPlaylist.PLAYLIST_TYPE_EVENT
|
||||||
|
|| playlistSnapshot.playlistType == HlsMediaPlaylist.PLAYLIST_TYPE_VOD
|
||||||
|| lastSnapshotLoadMs + snapshotValidityDurationMs > currentTimeMs;
|
|| lastSnapshotLoadMs + snapshotValidityDurationMs > currentTimeMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user