diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ca6914a763..ad9b18d73f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -18,9 +18,12 @@ * Error handling: * Allow configuration of the Loader retry delay ([#3370](https://github.com/google/ExoPlayer/issues/3370)). -* HLS: Pass HTTP response headers to `HlsExtractorFactory.createExtractor`. -* DRM: Allow DrmInitData to carry a license server URL - ([#3393](https://github.com/google/ExoPlayer/issues/3393)). +* HLS: + * Pass HTTP response headers to `HlsExtractorFactory.createExtractor`. + * 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 bandwidth information. * Add callback to `VideoListener` to notify of surface size changes. diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index 37804b81f4..4a8509d8ac 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -248,7 +248,7 @@ import java.util.List; return; } HlsMediaPlaylist mediaPlaylist = playlistTracker.getPlaylistSnapshot(selectedUrl); - independentSegments = mediaPlaylist.hasIndependentSegmentsTag; + independentSegments = mediaPlaylist.hasIndependentSegments; updateLiveEdgeTimeUs(mediaPlaylist); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java index 97a4ecc181..6e877b0321 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java @@ -544,6 +544,9 @@ public final class DefaultHlsPlaylistTracker } private void processLoadedPlaylist(HlsMediaPlaylist loadedPlaylist) { + // Update the loaded playlist with any inheritable information from the master playlist. + loadedPlaylist = loadedPlaylist.copyWithMasterPlaylistInfo(masterPlaylist); + HlsMediaPlaylist oldPlaylist = playlistSnapshot; long currentTimeMs = SystemClock.elapsedRealtime(); lastSnapshotLoadMs = currentTimeMs; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java index 1a3b1f583b..e5deb5068d 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java @@ -99,11 +99,18 @@ public final class HlsMasterPlaylist extends HlsPlaylist { * @param subtitles See {@link #subtitles}. * @param muxedAudioFormat See {@link #muxedAudioFormat}. * @param muxedCaptionFormats See {@link #muxedCaptionFormats}. + * @param hasIndependentSegments See {@link #hasIndependentSegments}. */ - public HlsMasterPlaylist(String baseUri, List tags, List variants, - List audios, List subtitles, Format muxedAudioFormat, - List muxedCaptionFormats) { - super(baseUri, tags); + public HlsMasterPlaylist( + String baseUri, + List tags, + List variants, + List audios, + List subtitles, + Format muxedAudioFormat, + List muxedCaptionFormats, + boolean hasIndependentSegments) { + super(baseUri, tags, hasIndependentSegments); this.variants = Collections.unmodifiableList(variants); this.audios = Collections.unmodifiableList(audios); this.subtitles = Collections.unmodifiableList(subtitles); @@ -121,7 +128,8 @@ public final class HlsMasterPlaylist extends HlsPlaylist { copyRenditionsList(audios, GROUP_INDEX_AUDIO, streamKeys), copyRenditionsList(subtitles, GROUP_INDEX_SUBTITLE, streamKeys), muxedAudioFormat, - muxedCaptionFormats); + muxedCaptionFormats, + hasIndependentSegments); } /** @@ -133,8 +141,15 @@ public final class HlsMasterPlaylist extends HlsPlaylist { public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) { List variant = Collections.singletonList(HlsUrl.createMediaPlaylistHlsUrl(variantUrl)); List emptyList = Collections.emptyList(); - return new HlsMasterPlaylist(null, Collections.emptyList(), variant, emptyList, - emptyList, null, null); + return new HlsMasterPlaylist( + null, + Collections.emptyList(), + variant, + emptyList, + emptyList, + /* muxedAudioFormat= */ null, + /* muxedCaptionFormats= */ null, + /* hasIndependentSegments= */ false); } private static List copyRenditionsList( diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index d54d433258..93e58c6371 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -174,10 +174,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * The target duration in microseconds, as defined by #EXT-X-TARGETDURATION. */ 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. */ @@ -211,7 +207,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * @param mediaSequence See {@link #mediaSequence}. * @param version See {@link #version}. * @param targetDurationUs See {@link #targetDurationUs}. - * @param hasIndependentSegmentsTag See {@link #hasIndependentSegmentsTag}. + * @param hasIndependentSegments See {@link #hasIndependentSegments}. * @param hasEndTag See {@link #hasEndTag}. * @param hasProgramDateTime See {@link #hasProgramDateTime}. * @param drmInitData See {@link #drmInitData}. @@ -228,12 +224,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist { long mediaSequence, int version, long targetDurationUs, - boolean hasIndependentSegmentsTag, + boolean hasIndependentSegments, boolean hasEndTag, boolean hasProgramDateTime, DrmInitData drmInitData, List segments) { - super(baseUri, tags); + super(baseUri, tags, hasIndependentSegments); this.playlistType = playlistType; this.startTimeUs = startTimeUs; this.hasDiscontinuitySequence = hasDiscontinuitySequence; @@ -241,7 +237,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist { this.mediaSequence = mediaSequence; this.version = version; this.targetDurationUs = targetDurationUs; - this.hasIndependentSegmentsTag = hasIndependentSegmentsTag; this.hasEndTag = hasEndTag; this.hasProgramDateTime = hasProgramDateTime; this.drmInitData = drmInitData; @@ -295,7 +290,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * * @param startTimeUs The start time 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) { return new HlsMediaPlaylist( @@ -309,7 +304,41 @@ public final class HlsMediaPlaylist extends HlsPlaylist { mediaSequence, version, 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}. + * + *

The inheritable attributes are: + * + *

    + *
  • {@link #hasIndependentSegments}. + *
+ * + * @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, hasProgramDateTime, 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 * already present then the playlist will return itself. - * - * @return The playlist. */ public HlsMediaPlaylist copyWithEndTag() { if (this.hasEndTag) { @@ -337,7 +364,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist { mediaSequence, version, targetDurationUs, - hasIndependentSegmentsTag, + hasIndependentSegments, /* hasEndTag= */ true, hasProgramDateTime, drmInitData, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java index 1b21d3d13c..9cec1cd33b 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylist.java @@ -30,14 +30,21 @@ public abstract class HlsPlaylist implements FilterableManifest { * The list of tags in the playlist. */ public final List 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 tags See {@link #tags}. + * @param hasIndependentSegments See {@link #hasIndependentSegments}. */ - protected HlsPlaylist(String baseUri, List tags) { + protected HlsPlaylist(String baseUri, List tags, boolean hasIndependentSegments) { this.baseUri = baseUri; this.tags = Collections.unmodifiableList(tags); + this.hasIndependentSegments = hasIndependentSegments; } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 7187bdb0ca..2a67108bf9 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -217,6 +217,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser muxedCaptionFormats = null; boolean noClosedCaptions = false; + boolean hasIndependentSegmentsTag = false; String line; while (iterator.hasNext()) { @@ -227,7 +228,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser