diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f9a03390ef..f21ad7f392 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,15 @@ # Release notes # +### 2.7.1 ### + +* HlsMediaSource: make HLS periods start at zero instead of the epoch. + Applications that rely on HLS timelines having a period starting at + the epoch will need to update their handling of HLS timelines. The program + date time is still available via the informational + `Timeline.Window.windowStartTimeMs` field + ([#3865](https://github.com/google/ExoPlayer/issues/3865), + [#3888](https://github.com/google/ExoPlayer/issues/3888)). + ### 2.7.0 ### * Player interface: @@ -21,7 +31,7 @@ * Add `ExoPlayer.setSeekParameters` for controlling how seek operations are performed. The `SeekParameters` class contains defaults for exact seeking and seeking to the closest sync points before, either side or after specified seek - positions. `SeekParameters` are not currently supported when playing HLS + positions. `SeekParameters` are not currently supported when playing HLS streams. * DefaultTrackSelector: * Replace `DefaultTrackSelector.Parameters` copy methods with a builder. 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 db0db47aee..d8496a63d2 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 @@ -261,9 +261,13 @@ import java.util.List; // If the playlist is too old to contain the chunk, we need to refresh it. chunkMediaSequence = mediaPlaylist.mediaSequence + mediaPlaylist.segments.size(); } else { - chunkMediaSequence = Util.binarySearchFloor(mediaPlaylist.segments, - targetPositionUs - mediaPlaylist.startTimeUs, true, - !playlistTracker.isLive() || previous == null) + mediaPlaylist.mediaSequence; + chunkMediaSequence = + Util.binarySearchFloor( + mediaPlaylist.segments, + targetPositionUs, + /* inclusive= */ true, + /* stayInBounds= */ !playlistTracker.isLive() || previous == null) + + mediaPlaylist.mediaSequence; if (chunkMediaSequence < mediaPlaylist.mediaSequence && previous != null) { // We try getting the next chunk without adapting in case that's the reason for falling // behind the live window. @@ -320,7 +324,9 @@ import java.util.List; } // Compute start time of the next chunk. - long startTimeUs = mediaPlaylist.startTimeUs + segment.relativeStartTimeUs; + long offsetFromInitialStartTimeUs = + mediaPlaylist.startTimeUs - playlistTracker.getInitialStartTimeUs(); + long startTimeUs = offsetFromInitialStartTimeUs + segment.relativeStartTimeUs; int discontinuitySequence = mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence; TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster( diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 5113bef6e0..1fe0d72ea1 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -366,28 +366,50 @@ public final class HlsMediaSource implements MediaSource, @Override public void onPrimaryPlaylistRefreshed(HlsMediaPlaylist playlist) { SinglePeriodTimeline timeline; - long presentationStartTimeMs = playlist.hasProgramDateTime ? 0 : C.TIME_UNSET; long windowStartTimeMs = playlist.hasProgramDateTime ? C.usToMs(playlist.startTimeUs) : C.TIME_UNSET; + // For playlist types EVENT and VOD we know segments are never removed, so the presentation + // started at the same time as the window. Otherwise, we don't know the presentation start time. + long presentationStartTimeMs = + playlist.playlistType == HlsMediaPlaylist.PLAYLIST_TYPE_EVENT + || playlist.playlistType == HlsMediaPlaylist.PLAYLIST_TYPE_VOD + ? windowStartTimeMs + : C.TIME_UNSET; long windowDefaultStartPositionUs = playlist.startOffsetUs; if (playlistTracker.isLive()) { - long periodDurationUs = playlist.hasEndTag ? (playlist.startTimeUs + playlist.durationUs) - : C.TIME_UNSET; + long offsetFromInitialStartTimeUs = + playlist.startTimeUs - playlistTracker.getInitialStartTimeUs(); + long periodDurationUs = + playlist.hasEndTag ? offsetFromInitialStartTimeUs + playlist.durationUs : C.TIME_UNSET; List segments = playlist.segments; if (windowDefaultStartPositionUs == C.TIME_UNSET) { windowDefaultStartPositionUs = segments.isEmpty() ? 0 : segments.get(Math.max(0, segments.size() - 3)).relativeStartTimeUs; } - timeline = new SinglePeriodTimeline(presentationStartTimeMs, windowStartTimeMs, - periodDurationUs, playlist.durationUs, playlist.startTimeUs, windowDefaultStartPositionUs, - true, !playlist.hasEndTag); + timeline = + new SinglePeriodTimeline( + presentationStartTimeMs, + windowStartTimeMs, + periodDurationUs, + /* windowDurationUs= */ playlist.durationUs, + /* windowPositionInPeriodUs= */ offsetFromInitialStartTimeUs, + windowDefaultStartPositionUs, + /* isSeekable= */ true, + /* isDynamic= */ !playlist.hasEndTag); } else /* not live */ { if (windowDefaultStartPositionUs == C.TIME_UNSET) { windowDefaultStartPositionUs = 0; } - timeline = new SinglePeriodTimeline(presentationStartTimeMs, windowStartTimeMs, - playlist.startTimeUs + playlist.durationUs, playlist.durationUs, playlist.startTimeUs, - windowDefaultStartPositionUs, true, false); + timeline = + new SinglePeriodTimeline( + presentationStartTimeMs, + windowStartTimeMs, + /* periodDurationUs= */ playlist.durationUs, + /* windowDurationUs= */ playlist.durationUs, + /* windowPositionInPeriodUs= */ 0, + windowDefaultStartPositionUs, + /* isSeekable= */ true, + /* isDynamic= */ false); } sourceListener.onSourceInfoRefreshed(this, timeline, new HlsManifest(playlistTracker.getMasterPlaylist(), playlist)); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java index d2f16b5c27..2e565c322a 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java @@ -83,7 +83,6 @@ public final class HlsPlaylistTracker implements Loader.Callback(); playlistRefreshHandler = new Handler(); + initialStartTimeUs = C.TIME_UNSET; } /** @@ -208,6 +209,11 @@ public final class HlsPlaylistTracker implements Loader.Callback