Support EXT-X-INDEPENDENT-SEGMENTS in the master playlist
From the spec: If the EXT-X-INDEPENDENT-SEGMENTS tag appears in a Master Playlist, it applies to every Media Segment in every Media Playlist in the Master Playlist. ---- This requires propagation of attributes from the master playlist to the media playlists. This CL only includes independent segments, but other inheritable attributes will be supported in following changes. Other inheritable attributes include variable substitution definitions and session keys. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=202628422
This commit is contained in:
parent
a916ad6a50
commit
efa714ab4f
@ -18,9 +18,12 @@
|
|||||||
* Error handling:
|
* Error handling:
|
||||||
* Allow configuration of the Loader retry delay
|
* Allow configuration of the Loader retry delay
|
||||||
([#3370](https://github.com/google/ExoPlayer/issues/3370)).
|
([#3370](https://github.com/google/ExoPlayer/issues/3370)).
|
||||||
* HLS: Pass HTTP response headers to `HlsExtractorFactory.createExtractor`.
|
* HLS:
|
||||||
* DRM: Allow DrmInitData to carry a license server URL
|
* Pass HTTP response headers to `HlsExtractorFactory.createExtractor`.
|
||||||
([#3393](https://github.com/google/ExoPlayer/issues/3393)).
|
* Add support for EXT-X-INDEPENDENT-SEGMENTS in the master playlist.
|
||||||
|
* DRM:
|
||||||
|
* Allow DrmInitData to carry a license server URL
|
||||||
|
([#3393](https://github.com/google/ExoPlayer/issues/3393)).
|
||||||
* Add method to `BandwidthMeter` to return the `TransferListener` used to gather
|
* Add method to `BandwidthMeter` to return the `TransferListener` used to gather
|
||||||
bandwidth information.
|
bandwidth information.
|
||||||
* Add callback to `VideoListener` to notify of surface size changes.
|
* Add callback to `VideoListener` to notify of surface size changes.
|
||||||
|
@ -248,7 +248,7 @@ import java.util.List;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HlsMediaPlaylist mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl);
|
HlsMediaPlaylist mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl);
|
||||||
independentSegments = mediaPlaylist.hasIndependentSegmentsTag;
|
independentSegments = mediaPlaylist.hasIndependentSegments;
|
||||||
|
|
||||||
updateLiveEdgeTimeUs(mediaPlaylist);
|
updateLiveEdgeTimeUs(mediaPlaylist);
|
||||||
|
|
||||||
|
@ -544,6 +544,9 @@ public final class DefaultHlsPlaylistTracker
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist) {
|
private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist) {
|
||||||
|
// Update the loaded playlist with any inheritable information from the master playlist.
|
||||||
|
loadedPlaylist = loadedPlaylist.copyWithMasterPlaylistInfo(masterPlaylist);
|
||||||
|
|
||||||
HlsMediaPlaylist oldPlaylist = playlistSnapshot;
|
HlsMediaPlaylist oldPlaylist = playlistSnapshot;
|
||||||
long currentTimeMs = SystemClock.elapsedRealtime();
|
long currentTimeMs = SystemClock.elapsedRealtime();
|
||||||
lastSnapshotLoadMs = currentTimeMs;
|
lastSnapshotLoadMs = currentTimeMs;
|
||||||
|
@ -99,11 +99,18 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
|
|||||||
* @param subtitles See {@link #subtitles}.
|
* @param subtitles See {@link #subtitles}.
|
||||||
* @param muxedAudioFormat See {@link #muxedAudioFormat}.
|
* @param muxedAudioFormat See {@link #muxedAudioFormat}.
|
||||||
* @param muxedCaptionFormats See {@link #muxedCaptionFormats}.
|
* @param muxedCaptionFormats See {@link #muxedCaptionFormats}.
|
||||||
|
* @param hasIndependentSegments See {@link #hasIndependentSegments}.
|
||||||
*/
|
*/
|
||||||
public HlsMasterPlaylist(String baseUri, List<String> tags, List<HlsUrl> variants,
|
public HlsMasterPlaylist(
|
||||||
List<HlsUrl> audios, List<HlsUrl> subtitles, Format muxedAudioFormat,
|
String baseUri,
|
||||||
List<Format> muxedCaptionFormats) {
|
List<String> tags,
|
||||||
super(baseUri, tags);
|
List<HlsUrl> variants,
|
||||||
|
List<HlsUrl> audios,
|
||||||
|
List<HlsUrl> subtitles,
|
||||||
|
Format muxedAudioFormat,
|
||||||
|
List<Format> muxedCaptionFormats,
|
||||||
|
boolean hasIndependentSegments) {
|
||||||
|
super(baseUri, tags, hasIndependentSegments);
|
||||||
this.variants = Collections.unmodifiableList(variants);
|
this.variants = Collections.unmodifiableList(variants);
|
||||||
this.audios = Collections.unmodifiableList(audios);
|
this.audios = Collections.unmodifiableList(audios);
|
||||||
this.subtitles = Collections.unmodifiableList(subtitles);
|
this.subtitles = Collections.unmodifiableList(subtitles);
|
||||||
@ -121,7 +128,8 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
|
|||||||
copyRenditionsList(audios, GROUP_INDEX_AUDIO, streamKeys),
|
copyRenditionsList(audios, GROUP_INDEX_AUDIO, streamKeys),
|
||||||
copyRenditionsList(subtitles, GROUP_INDEX_SUBTITLE, streamKeys),
|
copyRenditionsList(subtitles, GROUP_INDEX_SUBTITLE, streamKeys),
|
||||||
muxedAudioFormat,
|
muxedAudioFormat,
|
||||||
muxedCaptionFormats);
|
muxedCaptionFormats,
|
||||||
|
hasIndependentSegments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,8 +141,15 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
|
|||||||
public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) {
|
public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) {
|
||||||
List<HlsUrl> variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl));
|
List<HlsUrl> variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl));
|
||||||
List<HlsUrl> emptyList = Collections.emptyList();
|
List<HlsUrl> emptyList = Collections.emptyList();
|
||||||
return new HlsMasterPlaylist(null, Collections.<String>emptyList(), variant, emptyList,
|
return new HlsMasterPlaylist(
|
||||||
emptyList, null, null);
|
null,
|
||||||
|
Collections.<String>emptyList(),
|
||||||
|
variant,
|
||||||
|
emptyList,
|
||||||
|
emptyList,
|
||||||
|
/* muxedAudioFormat= */ null,
|
||||||
|
/* muxedCaptionFormats= */ null,
|
||||||
|
/* hasIndependentSegments= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<HlsUrl> copyRenditionsList(
|
private static List<HlsUrl> copyRenditionsList(
|
||||||
|
@ -174,10 +174,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
* The target duration in microseconds, as defined by #EXT-X-TARGETDURATION.
|
* The target duration in microseconds, as defined by #EXT-X-TARGETDURATION.
|
||||||
*/
|
*/
|
||||||
public final long targetDurationUs;
|
public final long targetDurationUs;
|
||||||
/**
|
|
||||||
* Whether the playlist contains the #EXT-X-INDEPENDENT-SEGMENTS tag.
|
|
||||||
*/
|
|
||||||
public final boolean hasIndependentSegmentsTag;
|
|
||||||
/**
|
/**
|
||||||
* Whether the playlist contains the #EXT-X-ENDLIST tag.
|
* Whether the playlist contains the #EXT-X-ENDLIST tag.
|
||||||
*/
|
*/
|
||||||
@ -211,7 +207,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
* @param mediaSequence See {@link #mediaSequence}.
|
* @param mediaSequence See {@link #mediaSequence}.
|
||||||
* @param version See {@link #version}.
|
* @param version See {@link #version}.
|
||||||
* @param targetDurationUs See {@link #targetDurationUs}.
|
* @param targetDurationUs See {@link #targetDurationUs}.
|
||||||
* @param hasIndependentSegmentsTag See {@link #hasIndependentSegmentsTag}.
|
* @param hasIndependentSegments See {@link #hasIndependentSegments}.
|
||||||
* @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}.
|
||||||
@ -228,12 +224,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
long mediaSequence,
|
long mediaSequence,
|
||||||
int version,
|
int version,
|
||||||
long targetDurationUs,
|
long targetDurationUs,
|
||||||
boolean hasIndependentSegmentsTag,
|
boolean hasIndependentSegments,
|
||||||
boolean hasEndTag,
|
boolean hasEndTag,
|
||||||
boolean hasProgramDateTime,
|
boolean hasProgramDateTime,
|
||||||
DrmInitData drmInitData,
|
DrmInitData drmInitData,
|
||||||
List<Segment> segments) {
|
List<Segment> segments) {
|
||||||
super(baseUri, tags);
|
super(baseUri, tags, hasIndependentSegments);
|
||||||
this.playlistType = playlistType;
|
this.playlistType = playlistType;
|
||||||
this.startTimeUs = startTimeUs;
|
this.startTimeUs = startTimeUs;
|
||||||
this.hasDiscontinuitySequence = hasDiscontinuitySequence;
|
this.hasDiscontinuitySequence = hasDiscontinuitySequence;
|
||||||
@ -241,7 +237,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
this.mediaSequence = mediaSequence;
|
this.mediaSequence = mediaSequence;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.targetDurationUs = targetDurationUs;
|
this.targetDurationUs = targetDurationUs;
|
||||||
this.hasIndependentSegmentsTag = hasIndependentSegmentsTag;
|
|
||||||
this.hasEndTag = hasEndTag;
|
this.hasEndTag = hasEndTag;
|
||||||
this.hasProgramDateTime = hasProgramDateTime;
|
this.hasProgramDateTime = hasProgramDateTime;
|
||||||
this.drmInitData = drmInitData;
|
this.drmInitData = drmInitData;
|
||||||
@ -295,7 +290,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
*
|
*
|
||||||
* @param startTimeUs The start time for the returned playlist.
|
* @param startTimeUs The start time for the returned playlist.
|
||||||
* @param discontinuitySequence The discontinuity sequence for the returned playlist.
|
* @param discontinuitySequence The discontinuity sequence for the returned playlist.
|
||||||
* @return The playlist.
|
* @return An identical playlist including the provided discontinuity and timing information.
|
||||||
*/
|
*/
|
||||||
public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) {
|
public HlsMediaPlaylist copyWith(long startTimeUs, int discontinuitySequence) {
|
||||||
return new HlsMediaPlaylist(
|
return new HlsMediaPlaylist(
|
||||||
@ -309,7 +304,41 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
mediaSequence,
|
mediaSequence,
|
||||||
version,
|
version,
|
||||||
targetDurationUs,
|
targetDurationUs,
|
||||||
hasIndependentSegmentsTag,
|
hasIndependentSegments,
|
||||||
|
hasEndTag,
|
||||||
|
hasProgramDateTime,
|
||||||
|
drmInitData,
|
||||||
|
segments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a playlist identical to this one, except for adding any inheritable attributes from the
|
||||||
|
* provided {@link HlsMasterPlaylist}.
|
||||||
|
*
|
||||||
|
* <p>The inheritable attributes are:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #hasIndependentSegments}.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @return An identical playlist including the inheritable attributes from {@code masterPlaylist}.
|
||||||
|
*/
|
||||||
|
public HlsMediaPlaylist copyWithMasterPlaylistInfo(HlsMasterPlaylist masterPlaylist) {
|
||||||
|
if (hasIndependentSegments || !masterPlaylist.hasIndependentSegments) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return new HlsMediaPlaylist(
|
||||||
|
playlistType,
|
||||||
|
baseUri,
|
||||||
|
tags,
|
||||||
|
startOffsetUs,
|
||||||
|
startTimeUs,
|
||||||
|
hasDiscontinuitySequence,
|
||||||
|
discontinuitySequence,
|
||||||
|
mediaSequence,
|
||||||
|
version,
|
||||||
|
targetDurationUs,
|
||||||
|
hasIndependentSegments || masterPlaylist.hasIndependentSegments,
|
||||||
hasEndTag,
|
hasEndTag,
|
||||||
hasProgramDateTime,
|
hasProgramDateTime,
|
||||||
drmInitData,
|
drmInitData,
|
||||||
@ -319,8 +348,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
/**
|
/**
|
||||||
* Returns a playlist identical to this one except that an end tag is added. If an end tag is
|
* Returns a playlist identical to this one except that an end tag is added. If an end tag is
|
||||||
* already present then the playlist will return itself.
|
* already present then the playlist will return itself.
|
||||||
*
|
|
||||||
* @return The playlist.
|
|
||||||
*/
|
*/
|
||||||
public HlsMediaPlaylist copyWithEndTag() {
|
public HlsMediaPlaylist copyWithEndTag() {
|
||||||
if (this.hasEndTag) {
|
if (this.hasEndTag) {
|
||||||
@ -337,7 +364,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
|||||||
mediaSequence,
|
mediaSequence,
|
||||||
version,
|
version,
|
||||||
targetDurationUs,
|
targetDurationUs,
|
||||||
hasIndependentSegmentsTag,
|
hasIndependentSegments,
|
||||||
/* hasEndTag= */ true,
|
/* hasEndTag= */ true,
|
||||||
hasProgramDateTime,
|
hasProgramDateTime,
|
||||||
drmInitData,
|
drmInitData,
|
||||||
|
@ -30,14 +30,21 @@ public abstract class HlsPlaylist implements FilterableManifest<HlsPlaylist> {
|
|||||||
* The list of tags in the playlist.
|
* The list of tags in the playlist.
|
||||||
*/
|
*/
|
||||||
public final List<String> tags;
|
public final List<String> tags;
|
||||||
|
/**
|
||||||
|
* Whether the media is formed of independent segments, as defined by the
|
||||||
|
* #EXT-X-INDEPENDENT-SEGMENTS tag.
|
||||||
|
*/
|
||||||
|
public final boolean hasIndependentSegments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param baseUri See {@link #baseUri}.
|
* @param baseUri See {@link #baseUri}.
|
||||||
* @param tags See {@link #tags}.
|
* @param tags See {@link #tags}.
|
||||||
|
* @param hasIndependentSegments See {@link #hasIndependentSegments}.
|
||||||
*/
|
*/
|
||||||
protected HlsPlaylist(String baseUri, List<String> tags) {
|
protected HlsPlaylist(String baseUri, List<String> tags, boolean hasIndependentSegments) {
|
||||||
this.baseUri = baseUri;
|
this.baseUri = baseUri;
|
||||||
this.tags = Collections.unmodifiableList(tags);
|
this.tags = Collections.unmodifiableList(tags);
|
||||||
|
this.hasIndependentSegments = hasIndependentSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
Format muxedAudioFormat = null;
|
Format muxedAudioFormat = null;
|
||||||
List<Format> muxedCaptionFormats = null;
|
List<Format> muxedCaptionFormats = null;
|
||||||
boolean noClosedCaptions = false;
|
boolean noClosedCaptions = false;
|
||||||
|
boolean hasIndependentSegmentsTag = false;
|
||||||
|
|
||||||
String line;
|
String line;
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
@ -227,7 +228,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
tags.add(line);
|
tags.add(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.startsWith(TAG_MEDIA)) {
|
if (line.equals(TAG_INDEPENDENT_SEGMENTS)) {
|
||||||
|
hasIndependentSegmentsTag = true;
|
||||||
|
} else if (line.startsWith(TAG_MEDIA)) {
|
||||||
// Media tags are parsed at the end to include codec information from #EXT-X-STREAM-INF
|
// Media tags are parsed at the end to include codec information from #EXT-X-STREAM-INF
|
||||||
// tags.
|
// tags.
|
||||||
mediaTags.add(line);
|
mediaTags.add(line);
|
||||||
@ -326,8 +329,15 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
|||||||
if (noClosedCaptions) {
|
if (noClosedCaptions) {
|
||||||
muxedCaptionFormats = Collections.emptyList();
|
muxedCaptionFormats = Collections.emptyList();
|
||||||
}
|
}
|
||||||
return new HlsMasterPlaylist(baseUri, tags, variants, audios, subtitles, muxedAudioFormat,
|
return new HlsMasterPlaylist(
|
||||||
muxedCaptionFormats);
|
baseUri,
|
||||||
|
tags,
|
||||||
|
variants,
|
||||||
|
audios,
|
||||||
|
subtitles,
|
||||||
|
muxedAudioFormat,
|
||||||
|
muxedCaptionFormats,
|
||||||
|
hasIndependentSegmentsTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@C.SelectionFlags
|
@C.SelectionFlags
|
||||||
|
@ -105,6 +105,18 @@ public class HlsMasterPlaylistParserTest {
|
|||||||
+ "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aud2\",LANGUAGE=\"en\",NAME=\"English\","
|
+ "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aud2\",LANGUAGE=\"en\",NAME=\"English\","
|
||||||
+ "AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"6\",URI=\"a2/prog_index.m3u8\"\n";
|
+ "AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"6\",URI=\"a2/prog_index.m3u8\"\n";
|
||||||
|
|
||||||
|
private static final String PLAYLIST_WITH_INDEPENDENT_SEGMENTS =
|
||||||
|
" #EXTM3U\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "#EXT-X-INDEPENDENT-SEGMENTS\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,"
|
||||||
|
+ "CODECS=\"mp4a.40.2,avc1.66.30\",RESOLUTION=304x128\n"
|
||||||
|
+ "http://example.com/low.m3u8\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS=\"mp4a.40.2 , avc1.66.30 \"\n"
|
||||||
|
+ "http://example.com/spaces_in_codecs.m3u8\n";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseMasterPlaylist() throws IOException {
|
public void testParseMasterPlaylist() throws IOException {
|
||||||
HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
|
HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
|
||||||
@ -195,6 +207,17 @@ public class HlsMasterPlaylistParserTest {
|
|||||||
assertThat(secondAudioFormat.sampleMimeType).isEqualTo(MimeTypes.AUDIO_AC3);
|
assertThat(secondAudioFormat.sampleMimeType).isEqualTo(MimeTypes.AUDIO_AC3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIndependentSegments() throws IOException {
|
||||||
|
HlsMasterPlaylist playlistWithIndependentSegments =
|
||||||
|
parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INDEPENDENT_SEGMENTS);
|
||||||
|
assertThat(playlistWithIndependentSegments.hasIndependentSegments).isTrue();
|
||||||
|
|
||||||
|
HlsMasterPlaylist playlistWithoutIndependentSegments =
|
||||||
|
parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
|
||||||
|
assertThat(playlistWithoutIndependentSegments.hasIndependentSegments).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString)
|
private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Uri playlistUri = Uri.parse(uri);
|
Uri playlistUri = Uri.parse(uri);
|
||||||
|
@ -25,6 +25,7 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -278,4 +279,42 @@ public class HlsMediaPlaylistParserTest {
|
|||||||
assertThat(segments.get(1).initializationSegment.url).isEqualTo("init1.ts");
|
assertThat(segments.get(1).initializationSegment.url).isEqualTo("init1.ts");
|
||||||
assertThat(segments.get(3).initializationSegment.url).isEqualTo("init2.ts");
|
assertThat(segments.get(3).initializationSegment.url).isEqualTo("init2.ts");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMasterPlaylistAttributeInheritance() 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);
|
||||||
|
assertThat(playlist.hasIndependentSegments).isFalse();
|
||||||
|
|
||||||
|
HlsMasterPlaylist masterPlaylist =
|
||||||
|
new HlsMasterPlaylist(
|
||||||
|
/* baseUri= */ "https://example.com/",
|
||||||
|
/* tags= */ Collections.emptyList(),
|
||||||
|
/* variants= */ Collections.emptyList(),
|
||||||
|
/* audios= */ Collections.emptyList(),
|
||||||
|
/* subtitles= */ Collections.emptyList(),
|
||||||
|
/* muxedAudioFormat= */ null,
|
||||||
|
/* muxedCaptionFormats= */ null,
|
||||||
|
/* hasIndependentSegments= */ true);
|
||||||
|
|
||||||
|
assertThat(playlist.copyWithMasterPlaylistInfo(masterPlaylist).hasIndependentSegments).isTrue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user