Commit ddef32c9 by aquilescanta Committed by Oliver Woodman

Support multiple EXT-X-MAP tags

Issue:#4182

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=194223312
parent dcff0637
......@@ -77,6 +77,8 @@
([#4145](https://github.com/google/ExoPlayer/issues/4145)).
* Preeptively declare an ID3 track in chunkless preparation
([#4016](https://github.com/google/ExoPlayer/issues/4016)).
* Add support for multiple #EXT-X-MAP tags in a media playlist
([#4164](https://github.com/google/ExoPlayer/issues/4182)).
* Fix ClearKey decryption error if the key contains a forward slash
([#4075](https://github.com/google/ExoPlayer/issues/4075)).
* Fix crash when switching surface on Huawei P9 Lite
......
......@@ -320,7 +320,7 @@ import java.util.List;
}
DataSpec initDataSpec = null;
Segment initSegment = mediaPlaylist.initializationSegment;
Segment initSegment = segment.initializationSegment;
if (initSegment != null) {
Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
initDataSpec = new DataSpec(initSegmentUri, initSegment.byterangeOffset,
......
......@@ -94,14 +94,16 @@ public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, Re
continue;
}
HlsMediaPlaylist.Segment initSegment = mediaPlaylist.initializationSegment;
if (initSegment != null) {
addSegment(segments, mediaPlaylist, initSegment, encryptionKeyUris);
}
HlsMediaPlaylist.Segment lastInitSegment = null;
List<HlsMediaPlaylist.Segment> hlsSegments = mediaPlaylist.segments;
for (int i = 0; i < hlsSegments.size(); i++) {
addSegment(segments, mediaPlaylist, hlsSegments.get(i), encryptionKeyUris);
HlsMediaPlaylist.Segment segment = hlsSegments.get(i);
HlsMediaPlaylist.Segment initSegment = segment.initializationSegment;
if (initSegment != null && initSegment != lastInitSegment) {
lastInitSegment = initSegment;
addSegment(segments, mediaPlaylist, initSegment, encryptionKeyUris);
}
addSegment(segments, mediaPlaylist, segment, encryptionKeyUris);
}
}
return segments;
......
......@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.hls.playlist;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData;
import java.lang.annotation.Retention;
......@@ -38,8 +39,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
*/
public final String url;
/**
* The duration of the segment in microseconds, as defined by #EXTINF.
* The media initialization section for this segment, as defined by #EXT-X-MAP. May be null if
* the media playlist does not define a media section for this segment. The same instance is
* used for all segments that share an EXT-X-MAP tag.
*/
@Nullable public final Segment initializationSegment;
/** The duration of the segment in microseconds, as defined by #EXTINF. */
public final long durationUs;
/**
* The number of #EXT-X-DISCONTINUITY tags in the playlist before the segment.
......@@ -78,11 +83,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* @param byterangeLength See {@link #byterangeLength}.
*/
public Segment(String uri, long byterangeOffset, long byterangeLength) {
this(uri, 0, -1, C.TIME_UNSET, null, null, byterangeOffset, byterangeLength, false);
this(uri, null, 0, -1, C.TIME_UNSET, null, null, byterangeOffset, byterangeLength, false);
}
/**
* @param url See {@link #url}.
* @param initializationSegment See {@link #initializationSegment}.
* @param durationUs See {@link #durationUs}.
* @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}.
* @param relativeStartTimeUs See {@link #relativeStartTimeUs}.
......@@ -94,6 +100,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
*/
public Segment(
String url,
Segment initializationSegment,
long durationUs,
int relativeDiscontinuitySequence,
long relativeStartTimeUs,
......@@ -103,6 +110,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
long byterangeLength,
boolean hasGapTag) {
this.url = url;
this.initializationSegment = initializationSegment;
this.durationUs = durationUs;
this.relativeDiscontinuitySequence = relativeDiscontinuitySequence;
this.relativeStartTimeUs = relativeStartTimeUs;
......@@ -183,10 +191,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
*/
public final DrmInitData drmInitData;
/**
* The initialization segment, as defined by #EXT-X-MAP.
*/
public final Segment initializationSegment;
/**
* The list of segments in the playlist.
*/
public final List<Segment> segments;
......@@ -210,7 +214,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* @param hasEndTag See {@link #hasEndTag}.
* @param hasProgramDateTime See {@link #hasProgramDateTime}.
* @param drmInitData See {@link #drmInitData}.
* @param initializationSegment See {@link #initializationSegment}.
* @param segments See {@link #segments}.
*/
public HlsMediaPlaylist(
......@@ -228,7 +231,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
boolean hasEndTag,
boolean hasProgramDateTime,
DrmInitData drmInitData,
Segment initializationSegment,
List<Segment> segments) {
super(baseUri, tags);
this.playlistType = playlistType;
......@@ -242,7 +244,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this.hasEndTag = hasEndTag;
this.hasProgramDateTime = hasProgramDateTime;
this.drmInitData = drmInitData;
this.initializationSegment = initializationSegment;
this.segments = Collections.unmodifiableList(segments);
if (!segments.isEmpty()) {
Segment last = segments.get(segments.size() - 1);
......@@ -296,9 +297,22 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* @return The playlist.
*/
public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) {
return new HlsMediaPlaylist(playlistType, baseUri, tags, startOffsetUs, startTimeUs, true,
discontinuitySequence, mediaSequence, version, targetDurationUs, hasIndependentSegmentsTag,
hasEndTag, hasProgramDateTime, drmInitData, initializationSegment, segments);
return new HlsMediaPlaylist(
playlistType,
baseUri,
tags,
startOffsetUs,
startTimeUs,
/* hasDiscontinuitySequence= */ true,
discontinuitySequence,
mediaSequence,
version,
targetDurationUs,
hasIndependentSegmentsTag,
hasEndTag,
hasProgramDateTime,
drmInitData,
segments);
}
/**
......@@ -311,9 +325,21 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
if (this.hasEndTag) {
return this;
}
return new HlsMediaPlaylist(playlistType, baseUri, tags, startOffsetUs, startTimeUs,
hasDiscontinuitySequence, discontinuitySequence, mediaSequence, version, targetDurationUs,
hasIndependentSegmentsTag, true, hasProgramDateTime, drmInitData, initializationSegment,
return new HlsMediaPlaylist(
playlistType,
baseUri,
tags,
startOffsetUs,
startTimeUs,
hasDiscontinuitySequence,
discontinuitySequence,
mediaSequence,
version,
targetDurationUs,
hasIndependentSegmentsTag,
/* hasEndTag= */ true,
hasProgramDateTime,
drmInitData,
segments);
}
......
......@@ -474,6 +474,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
segments.add(
new Segment(
line,
initializationSegment,
segmentDurationUs,
relativeDiscontinuitySequence,
segmentStartTimeUs,
......@@ -491,10 +492,22 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
hasGapTag = false;
}
}
return new HlsMediaPlaylist(playlistType, baseUri, tags, startOffsetUs, playlistStartTimeUs,
hasDiscontinuitySequence, playlistDiscontinuitySequence, mediaSequence, version,
targetDurationUs, hasIndependentSegmentsTag, hasEndTag, playlistStartTimeUs != 0,
drmInitData, initializationSegment, segments);
return new HlsMediaPlaylist(
playlistType,
baseUri,
tags,
startOffsetUs,
playlistStartTimeUs,
hasDiscontinuitySequence,
playlistDiscontinuitySequence,
mediaSequence,
version,
targetDurationUs,
hasIndependentSegmentsTag,
hasEndTag,
/* hasProgramDateTime= */ playlistStartTimeUs != 0,
drmInitData,
segments);
}
private static SchemeData parseWidevineSchemeData(String line, String keyFormat)
......
......@@ -247,4 +247,35 @@ public class HlsMediaPlaylistParserTest {
assertThat(playlist.segments.get(2).hasGapTag).isTrue();
assertThat(playlist.segments.get(3).hasGapTag).isFalse();
}
@Test
public void testMapTag() throws IOException {
Uri playlistUri = Uri.parse("https://example.com/test3.m3u8");
String playlistString =
"#EXTM3U\n"
+ "#EXT-X-VERSION:3\n"
+ "#EXT-X-TARGETDURATION:5\n"
+ "#EXT-X-MEDIA-SEQUENCE:10\n"
+ "#EXTINF:5.005,\n"
+ "02/00/27.ts\n"
+ "#EXT-X-MAP:URI=\"init1.ts\""
+ "#EXTINF:5.005,\n"
+ "02/00/32.ts\n"
+ "#EXTINF:5.005,\n"
+ "02/00/42.ts\n"
+ "#EXT-X-MAP:URI=\"init2.ts\""
+ "#EXTINF:5.005,\n"
+ "02/00/47.ts\n";
InputStream inputStream =
new ByteArrayInputStream(playlistString.getBytes(Charset.forName(C.UTF8_NAME)));
HlsMediaPlaylist playlist =
(HlsMediaPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
List<Segment> segments = playlist.segments;
assertThat(segments.get(0).initializationSegment).isNull();
assertThat(segments.get(1).initializationSegment)
.isSameAs(segments.get(2).initializationSegment);
assertThat(segments.get(1).initializationSegment.url).isEqualTo("init1.ts");
assertThat(segments.get(3).initializationSegment.url).isEqualTo("init2.ts");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment