mirror of
https://github.com/samsonjs/media.git
synced 2026-03-29 10:05:48 +00:00
Make the period and initial window positions match for all HLS streams
Before this change, HlsMediaSource timelines had a period starting at the epoch. For VOD streams the window position in the period was the program date time. This change makes period and initial window positions match. For live streams the window position advances as segments are removed, so its position in the period is the difference between the initial program date time and the program date time of the latest playlist. This also makes it possible to insert ads in VOD HLS content with program date time, as the period and window are now aligned. Issue: #3865 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=187590948
This commit is contained in:
parent
452e4debcc
commit
d8d3bd7b3f
4 changed files with 60 additions and 15 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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<HlsMediaPlaylist.Segment> 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));
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
|||
* @param mediaPlaylist The primary playlist new snapshot.
|
||||
*/
|
||||
void onPrimaryPlaylistRefreshed(HlsMediaPlaylist mediaPlaylist);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -128,6 +127,7 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
|||
private HlsUrl primaryHlsUrl;
|
||||
private HlsMediaPlaylist primaryUrlSnapshot;
|
||||
private boolean isLive;
|
||||
private long initialStartTimeUs;
|
||||
|
||||
/**
|
||||
* @param initialPlaylistUri Uri for the initial playlist of the stream. Can refer a media
|
||||
|
|
@ -153,6 +153,7 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
|||
initialPlaylistLoader = new Loader("HlsPlaylistTracker:MasterPlaylist");
|
||||
playlistBundles = new IdentityHashMap<>();
|
||||
playlistRefreshHandler = new Handler();
|
||||
initialStartTimeUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -208,6 +209,11 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
|||
return snapshot;
|
||||
}
|
||||
|
||||
/** Returns the start time of the first loaded primary playlist. */
|
||||
public long getInitialStartTimeUs() {
|
||||
return initialStartTimeUs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the snapshot of the playlist referenced by the provided {@link HlsUrl} is
|
||||
* valid, meaning all the segments referenced by the playlist are expected to be available. If the
|
||||
|
|
@ -371,6 +377,7 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
|||
if (primaryUrlSnapshot == null) {
|
||||
// This is the first primary url snapshot.
|
||||
isLive = !newSnapshot.hasEndTag;
|
||||
initialStartTimeUs = newSnapshot.startTimeUs;
|
||||
}
|
||||
primaryUrlSnapshot = newSnapshot;
|
||||
primaryPlaylistListener.onPrimaryPlaylistRefreshed(newSnapshot);
|
||||
|
|
|
|||
Loading…
Reference in a new issue