Add support for #EXT-X-START tag

This overrides the start position relative to the window.

Issue:#1544

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144434903
This commit is contained in:
aquilescanta 2017-01-13 06:07:04 -08:00 committed by Oliver Woodman
parent 63123f455c
commit 28e117d25f
3 changed files with 25 additions and 12 deletions

View file

@ -104,17 +104,23 @@ public final class HlsMediaSource implements MediaSource,
@Override @Override
public void onPrimaryPlaylistRefreshed(HlsMediaPlaylist playlist) { public void onPrimaryPlaylistRefreshed(HlsMediaPlaylist playlist) {
SinglePeriodTimeline timeline; SinglePeriodTimeline timeline;
long windowDefaultStartPositionUs = playlist.startOffsetUs;
if (playlistTracker.isLive()) { if (playlistTracker.isLive()) {
long periodDurationUs = playlist.hasEndTag ? (playlist.startTimeUs + playlist.durationUs) long periodDurationUs = playlist.hasEndTag ? (playlist.startTimeUs + playlist.durationUs)
: C.TIME_UNSET; : C.TIME_UNSET;
List<HlsMediaPlaylist.Segment> segments = playlist.segments; List<HlsMediaPlaylist.Segment> segments = playlist.segments;
long windowDefaultStartPositionUs = segments.isEmpty() ? 0 if (windowDefaultStartPositionUs == C.TIME_UNSET) {
: segments.get(Math.max(0, segments.size() - 3)).relativeStartTimeUs; windowDefaultStartPositionUs = segments.isEmpty() ? 0
: segments.get(Math.max(0, segments.size() - 3)).relativeStartTimeUs;
}
timeline = new SinglePeriodTimeline(periodDurationUs, playlist.durationUs, timeline = new SinglePeriodTimeline(periodDurationUs, playlist.durationUs,
playlist.startTimeUs, windowDefaultStartPositionUs, true, !playlist.hasEndTag); playlist.startTimeUs, windowDefaultStartPositionUs, true, !playlist.hasEndTag);
} else /* not live */ { } else /* not live */ {
if (windowDefaultStartPositionUs == C.TIME_UNSET) {
windowDefaultStartPositionUs = 0;
}
timeline = new SinglePeriodTimeline(playlist.startTimeUs + playlist.durationUs, timeline = new SinglePeriodTimeline(playlist.startTimeUs + playlist.durationUs,
playlist.durationUs, playlist.startTimeUs, 0, true, false); playlist.durationUs, playlist.startTimeUs, windowDefaultStartPositionUs, true, false);
} }
sourceListener.onSourceInfoRefreshed(timeline, playlist); sourceListener.onSourceInfoRefreshed(timeline, playlist);
} }

View file

@ -65,6 +65,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
} }
public final long startOffsetUs;
public final long startTimeUs; public final long startTimeUs;
public final int mediaSequence; public final int mediaSequence;
public final int version; public final int version;
@ -75,7 +76,7 @@ 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 startTimeUs, int mediaSequence, public HlsMediaPlaylist(String baseUri, long startOffsetUs, long startTimeUs, int mediaSequence,
int version, long targetDurationUs, boolean hasEndTag, boolean hasProgramDateTime, int version, long targetDurationUs, boolean hasEndTag, boolean hasProgramDateTime,
Segment initializationSegment, List<Segment> segments) { Segment initializationSegment, List<Segment> segments) {
super(baseUri, HlsPlaylist.TYPE_MEDIA); super(baseUri, HlsPlaylist.TYPE_MEDIA);
@ -87,13 +88,14 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this.hasProgramDateTime = hasProgramDateTime; this.hasProgramDateTime = hasProgramDateTime;
this.initializationSegment = initializationSegment; this.initializationSegment = initializationSegment;
this.segments = Collections.unmodifiableList(segments); this.segments = Collections.unmodifiableList(segments);
if (!segments.isEmpty()) { if (!segments.isEmpty()) {
Segment last = segments.get(segments.size() - 1); Segment last = segments.get(segments.size() - 1);
durationUs = last.relativeStartTimeUs + last.durationUs; durationUs = last.relativeStartTimeUs + last.durationUs;
} else { } else {
durationUs = 0; durationUs = 0;
} }
this.startOffsetUs = startOffsetUs == C.TIME_UNSET ? C.TIME_UNSET
: startOffsetUs >= 0 ? startOffsetUs : durationUs + startOffsetUs;
} }
/** /**
@ -132,8 +134,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
if (this.startTimeUs == startTimeUs) { if (this.startTimeUs == startTimeUs) {
return this; return this;
} }
return new HlsMediaPlaylist(baseUri, startTimeUs, mediaSequence, version, targetDurationUs, return new HlsMediaPlaylist(baseUri, startOffsetUs, startTimeUs, mediaSequence, version,
hasEndTag, hasProgramDateTime, initializationSegment, segments); targetDurationUs, hasEndTag, hasProgramDateTime, initializationSegment, segments);
} }
/** /**
@ -146,8 +148,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
if (this.hasEndTag) { if (this.hasEndTag) {
return this; return this;
} }
return new HlsMediaPlaylist(baseUri, startTimeUs, mediaSequence, version, targetDurationUs, return new HlsMediaPlaylist(baseUri, startOffsetUs, startTimeUs, mediaSequence, version,
true, hasProgramDateTime, initializationSegment, segments); targetDurationUs, true, hasProgramDateTime, initializationSegment, segments);
} }
} }

View file

@ -58,13 +58,14 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
private static final String TAG_VERSION = "#EXT-X-VERSION"; private static final String TAG_VERSION = "#EXT-X-VERSION";
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_DISCONTINUITY = "#EXT-X-DISCONTINUITY"; private static final String TAG_DISCONTINUITY = "#EXT-X-DISCONTINUITY";
private static final String TAG_DISCONTINUITY_SEQUENCE = "#EXT-X-DISCONTINUITY-SEQUENCE"; private static final String TAG_DISCONTINUITY_SEQUENCE = "#EXT-X-DISCONTINUITY-SEQUENCE";
private static final String TAG_PROGRAM_DATE_TIME = "#EXT-X-PROGRAM-DATE-TIME"; private static final String TAG_PROGRAM_DATE_TIME = "#EXT-X-PROGRAM-DATE-TIME";
private static final String TAG_INIT_SEGMENT = "#EXT-X-MAP"; private static final String TAG_INIT_SEGMENT = "#EXT-X-MAP";
private static final String TAG_MEDIA_DURATION = "#EXTINF"; private static final String TAG_MEDIA_DURATION = "#EXTINF";
private static final String TAG_MEDIA_SEQUENCE = "#EXT-X-MEDIA-SEQUENCE"; private static final String TAG_MEDIA_SEQUENCE = "#EXT-X-MEDIA-SEQUENCE";
private static final String TAG_TARGET_DURATION = "#EXT-X-TARGETDURATION"; private static final String TAG_START = "#EXT-X-START";
private static final String TAG_ENDLIST = "#EXT-X-ENDLIST"; private static final String TAG_ENDLIST = "#EXT-X-ENDLIST";
private static final String TAG_KEY = "#EXT-X-KEY"; private static final String TAG_KEY = "#EXT-X-KEY";
private static final String TAG_BYTERANGE = "#EXT-X-BYTERANGE"; private static final String TAG_BYTERANGE = "#EXT-X-BYTERANGE";
@ -90,6 +91,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
+ ":(\\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
+ ":([\\d\\.]+)\\b"); + ":([\\d\\.]+)\\b");
private static final Pattern REGEX_TIME_OFFSET = Pattern.compile("TIME-OFFSET=([\\d\\.]+)\\b");
private static final Pattern REGEX_BYTERANGE = Pattern.compile(TAG_BYTERANGE private static final Pattern REGEX_BYTERANGE = Pattern.compile(TAG_BYTERANGE
+ ":(\\d+(?:@\\d+)?)\\b"); + ":(\\d+(?:@\\d+)?)\\b");
private static final Pattern REGEX_ATTR_BYTERANGE = private static final Pattern REGEX_ATTR_BYTERANGE =
@ -255,6 +257,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 {
long startOffsetUs = C.TIME_UNSET;
int mediaSequence = 0; int mediaSequence = 0;
int version = 1; // Default version == 1. int version = 1; // Default version == 1.
long targetDurationUs = C.TIME_UNSET; long targetDurationUs = C.TIME_UNSET;
@ -277,7 +280,9 @@ 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_INIT_SEGMENT)) { 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 uri = parseStringAttr(line, REGEX_URI);
String byteRange = parseOptionalStringAttr(line, REGEX_ATTR_BYTERANGE); String byteRange = parseOptionalStringAttr(line, REGEX_ATTR_BYTERANGE);
if (byteRange != null) { if (byteRange != null) {
@ -353,7 +358,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
hasEndTag = true; hasEndTag = true;
} }
} }
return new HlsMediaPlaylist(baseUri, playlistStartTimeUs, mediaSequence, version, return new HlsMediaPlaylist(baseUri, startOffsetUs, playlistStartTimeUs, mediaSequence, version,
targetDurationUs, hasEndTag, playlistStartTimeUs != 0, initializationSegment, segments); targetDurationUs, hasEndTag, playlistStartTimeUs != 0, initializationSegment, segments);
} }