Support multiple EXT-X-MAP tags

Issue:#4182

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=194223312
This commit is contained in:
aquilescanta 2018-04-25 04:38:57 -07:00 committed by Oliver Woodman
parent dcff063709
commit ddef32c9e2
6 changed files with 100 additions and 26 deletions

View File

@ -77,6 +77,8 @@
([#4145](https://github.com/google/ExoPlayer/issues/4145)). ([#4145](https://github.com/google/ExoPlayer/issues/4145)).
* Preeptively declare an ID3 track in chunkless preparation * Preeptively declare an ID3 track in chunkless preparation
([#4016](https://github.com/google/ExoPlayer/issues/4016)). ([#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 * Fix ClearKey decryption error if the key contains a forward slash
([#4075](https://github.com/google/ExoPlayer/issues/4075)). ([#4075](https://github.com/google/ExoPlayer/issues/4075)).
* Fix crash when switching surface on Huawei P9 Lite * Fix crash when switching surface on Huawei P9 Lite

View File

@ -320,7 +320,7 @@ import java.util.List;
} }
DataSpec initDataSpec = null; DataSpec initDataSpec = null;
Segment initSegment = mediaPlaylist.initializationSegment; Segment initSegment = segment.initializationSegment;
if (initSegment != null) { if (initSegment != null) {
Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url); Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
initDataSpec = new DataSpec(initSegmentUri, initSegment.byterangeOffset, initDataSpec = new DataSpec(initSegmentUri, initSegment.byterangeOffset,

View File

@ -94,14 +94,16 @@ public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, Re
continue; continue;
} }
HlsMediaPlaylist.Segment initSegment = mediaPlaylist.initializationSegment; HlsMediaPlaylist.Segment lastInitSegment = null;
if (initSegment != null) {
addSegment(segments, mediaPlaylist, initSegment, encryptionKeyUris);
}
List<HlsMediaPlaylist.Segment> hlsSegments = mediaPlaylist.segments; List<HlsMediaPlaylist.Segment> hlsSegments = mediaPlaylist.segments;
for (int i = 0; i < hlsSegments.size(); i++) { 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; return segments;

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.hls.playlist;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -38,8 +39,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
*/ */
public final String url; 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; public final long durationUs;
/** /**
* The number of #EXT-X-DISCONTINUITY tags in the playlist before the segment. * 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}. * @param byterangeLength See {@link #byterangeLength}.
*/ */
public Segment(String uri, long byterangeOffset, long 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 url See {@link #url}.
* @param initializationSegment See {@link #initializationSegment}.
* @param durationUs See {@link #durationUs}. * @param durationUs See {@link #durationUs}.
* @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}. * @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}.
* @param relativeStartTimeUs See {@link #relativeStartTimeUs}. * @param relativeStartTimeUs See {@link #relativeStartTimeUs}.
@ -94,6 +100,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
*/ */
public Segment( public Segment(
String url, String url,
Segment initializationSegment,
long durationUs, long durationUs,
int relativeDiscontinuitySequence, int relativeDiscontinuitySequence,
long relativeStartTimeUs, long relativeStartTimeUs,
@ -103,6 +110,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
long byterangeLength, long byterangeLength,
boolean hasGapTag) { boolean hasGapTag) {
this.url = url; this.url = url;
this.initializationSegment = initializationSegment;
this.durationUs = durationUs; this.durationUs = durationUs;
this.relativeDiscontinuitySequence = relativeDiscontinuitySequence; this.relativeDiscontinuitySequence = relativeDiscontinuitySequence;
this.relativeStartTimeUs = relativeStartTimeUs; this.relativeStartTimeUs = relativeStartTimeUs;
@ -182,10 +190,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* encryption. * encryption.
*/ */
public final DrmInitData drmInitData; public final DrmInitData drmInitData;
/**
* The initialization segment, as defined by #EXT-X-MAP.
*/
public final Segment initializationSegment;
/** /**
* The list of segments in the playlist. * The list of segments in the playlist.
*/ */
@ -210,7 +214,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* @param hasEndTag See {@link #hasEndTag}. * @param hasEndTag See {@link #hasEndTag}.
* @param hasProgramDateTime See {@link #hasProgramDateTime}. * @param hasProgramDateTime See {@link #hasProgramDateTime}.
* @param drmInitData See {@link #drmInitData}. * @param drmInitData See {@link #drmInitData}.
* @param initializationSegment See {@link #initializationSegment}.
* @param segments See {@link #segments}. * @param segments See {@link #segments}.
*/ */
public HlsMediaPlaylist( public HlsMediaPlaylist(
@ -228,7 +231,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
boolean hasEndTag, boolean hasEndTag,
boolean hasProgramDateTime, boolean hasProgramDateTime,
DrmInitData drmInitData, DrmInitData drmInitData,
Segment initializationSegment,
List<Segment> segments) { List<Segment> segments) {
super(baseUri, tags); super(baseUri, tags);
this.playlistType = playlistType; this.playlistType = playlistType;
@ -242,7 +244,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this.hasEndTag = hasEndTag; this.hasEndTag = hasEndTag;
this.hasProgramDateTime = hasProgramDateTime; this.hasProgramDateTime = hasProgramDateTime;
this.drmInitData = drmInitData; this.drmInitData = drmInitData;
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);
@ -296,9 +297,22 @@ 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(playlistType, baseUri, tags, startOffsetUs, startTimeUs, true, return new HlsMediaPlaylist(
discontinuitySequence, mediaSequence, version, targetDurationUs, hasIndependentSegmentsTag, playlistType,
hasEndTag, hasProgramDateTime, drmInitData, initializationSegment, segments); 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) { if (this.hasEndTag) {
return this; return this;
} }
return new HlsMediaPlaylist(playlistType, baseUri, tags, startOffsetUs, startTimeUs, return new HlsMediaPlaylist(
hasDiscontinuitySequence, discontinuitySequence, mediaSequence, version, targetDurationUs, playlistType,
hasIndependentSegmentsTag, true, hasProgramDateTime, drmInitData, initializationSegment, baseUri,
tags,
startOffsetUs,
startTimeUs,
hasDiscontinuitySequence,
discontinuitySequence,
mediaSequence,
version,
targetDurationUs,
hasIndependentSegmentsTag,
/* hasEndTag= */ true,
hasProgramDateTime,
drmInitData,
segments); segments);
} }

View File

@ -474,6 +474,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
segments.add( segments.add(
new Segment( new Segment(
line, line,
initializationSegment,
segmentDurationUs, segmentDurationUs,
relativeDiscontinuitySequence, relativeDiscontinuitySequence,
segmentStartTimeUs, segmentStartTimeUs,
@ -491,10 +492,22 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
hasGapTag = false; hasGapTag = false;
} }
} }
return new HlsMediaPlaylist(playlistType, baseUri, tags, startOffsetUs, playlistStartTimeUs, return new HlsMediaPlaylist(
hasDiscontinuitySequence, playlistDiscontinuitySequence, mediaSequence, version, playlistType,
targetDurationUs, hasIndependentSegmentsTag, hasEndTag, playlistStartTimeUs != 0, baseUri,
drmInitData, initializationSegment, segments); tags,
startOffsetUs,
playlistStartTimeUs,
hasDiscontinuitySequence,
playlistDiscontinuitySequence,
mediaSequence,
version,
targetDurationUs,
hasIndependentSegmentsTag,
hasEndTag,
/* hasProgramDateTime= */ playlistStartTimeUs != 0,
drmInitData,
segments);
} }
private static SchemeData parseWidevineSchemeData(String line, String keyFormat) private static SchemeData parseWidevineSchemeData(String line, String keyFormat)

View File

@ -247,4 +247,35 @@ public class HlsMediaPlaylistParserTest {
assertThat(playlist.segments.get(2).hasGapTag).isTrue(); assertThat(playlist.segments.get(2).hasGapTag).isTrue();
assertThat(playlist.segments.get(3).hasGapTag).isFalse(); 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");
}
} }