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)).
* 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

View File

@ -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,

View File

@ -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;

View File

@ -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;
@ -182,10 +190,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* encryption.
*/
public final DrmInitData drmInitData;
/**
* The initialization segment, as defined by #EXT-X-MAP.
*/
public final Segment initializationSegment;
/**
* The list of segments in the playlist.
*/
@ -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);
}

View File

@ -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)

View File

@ -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");
}
}