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:
parent
dcff063709
commit
ddef32c9e2
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user