Skip to content

Commit

Permalink
Make the period and initial window positions match for all HLS streams
Browse files Browse the repository at this point in the history
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
  • Loading branch information
andrewlewis authored and ojw28 committed Mar 7, 2018
1 parent 452e4de commit d8d3bd7
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 15 deletions.
12 changes: 11 additions & 1 deletion RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,13 @@ public void getNextChunk(HlsMediaChunk previous, long playbackPositionUs, long l
// 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.
Expand Down Expand Up @@ -320,7 +324,9 @@ public void getNextChunk(HlsMediaChunk previous, long playbackPositionUs, long l
}

// 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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,28 +366,50 @@ public void releaseSource() {
@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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ public interface PrimaryPlaylistListener {
* @param mediaPlaylist The primary playlist new snapshot.
*/
void onPrimaryPlaylistRefreshed(HlsMediaPlaylist mediaPlaylist);

}

/**
Expand Down Expand Up @@ -128,6 +127,7 @@ public interface PlaylistEventListener {
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
Expand All @@ -153,6 +153,7 @@ public HlsPlaylistTracker(Uri initialPlaylistUri, HlsDataSourceFactory dataSourc
initialPlaylistLoader = new Loader("HlsPlaylistTracker:MasterPlaylist");
playlistBundles = new IdentityHashMap<>();
playlistRefreshHandler = new Handler();
initialStartTimeUs = C.TIME_UNSET;
}

/**
Expand Down Expand Up @@ -208,6 +209,11 @@ public HlsMediaPlaylist getPlaylistSnapshot(HlsUrl url) {
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
Expand Down Expand Up @@ -371,6 +377,7 @@ private void onPlaylistUpdated(HlsUrl url, HlsMediaPlaylist newSnapshot) {
if (primaryUrlSnapshot == null) {
// This is the first primary url snapshot.
isLive = !newSnapshot.hasEndTag;
initialStartTimeUs = newSnapshot.startTimeUs;
}
primaryUrlSnapshot = newSnapshot;
primaryPlaylistListener.onPrimaryPlaylistRefreshed(newSnapshot);
Expand Down

0 comments on commit d8d3bd7

Please sign in to comment.