Skip to content
This repository has been archived by the owner on Jan 12, 2019. It is now read-only.

Commit

Permalink
Use specified mediasequence for VOD expired sync instead of assuming 0 (
Browse files Browse the repository at this point in the history
#1097)

* use specified mediasequence for VOD expired sync instead of assuming 0

* use synccontroller for expired

* target sync-point by index for expired instead of time 0

* minor fixes

* add vod test for expired
  • Loading branch information
mjneil authored and dmlap committed May 4, 2017
1 parent 4daa28f commit 016d82f
Show file tree
Hide file tree
Showing 6 changed files with 437 additions and 137 deletions.
31 changes: 26 additions & 5 deletions src/master-playlist-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -1085,9 +1085,15 @@ export class MasterPlaylistController extends videojs.EventTarget {
return false;
}

let expired = this.syncController_.getExpiredTime(playlist, this.mediaSource.duration);

if (expired === null) {
return false;
}

// does not use the safe live end to calculate playlist end, since we
// don't want to say we are stuck while there is still content
let absolutePlaylistEnd = Hls.Playlist.playlistEnd(playlist);
let absolutePlaylistEnd = Hls.Playlist.playlistEnd(playlist, expired);
let currentTime = this.tech_.currentTime();
let buffered = this.tech_.buffered();

Expand Down Expand Up @@ -1251,27 +1257,42 @@ export class MasterPlaylistController extends videojs.EventTarget {
}

onSyncInfoUpdate_() {
let media;
let mainSeekable;
let audioSeekable;

if (!this.masterPlaylistLoader_) {
return;
}

media = this.masterPlaylistLoader_.media();
let media = this.masterPlaylistLoader_.media();

if (!media) {
return;
}

mainSeekable = Hls.Playlist.seekable(media);
let expired = this.syncController_.getExpiredTime(media, this.mediaSource.duration);

if (expired === null) {
// not enough information to update seekable
return;
}

mainSeekable = Hls.Playlist.seekable(media, expired);

if (mainSeekable.length === 0) {
return;
}

if (this.audioPlaylistLoader_) {
audioSeekable = Hls.Playlist.seekable(this.audioPlaylistLoader_.media());
media = this.audioPlaylistLoader_.media();
expired = this.syncController_.getExpiredTime(media, this.mediaSource.duration);

if (expired === null) {
return;
}

audioSeekable = Hls.Playlist.seekable(media, expired);

if (audioSeekable.length === 0) {
return;
}
Expand Down
105 changes: 11 additions & 94 deletions src/playlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,118 +219,33 @@ export const sumDurations = function(playlist, startIndex, endIndex) {
return durations;
};

/**
* Returns an array with two sync points. The first being an expired sync point, which is
* the most recent segment with timing sync data that has fallen off the playlist. The
* second is a segment sync point, which is the first segment that has timing sync data in
* the current playlist.
*
* @param {Object} playlist a media playlist object
* @returns {Object} an object containing the two sync points
* @returns {Object.expiredSync|null} sync point data from an expired segment
* @returns {Object.segmentSync|null} sync point data from a segment in the playlist
* @function getPlaylistSyncPoints
*/
const getPlaylistSyncPoints = function(playlist) {
if (!playlist || !playlist.segments) {
return [null, null];
}
let expiredSync = playlist.syncInfo || (playlist.endList ? { time: 0, mediaSequence: 0} : null);
let segmentSync = null;

// Find the first segment with timing information
for (let i = 0, l = playlist.segments.length; i < l; i++) {
let segment = playlist.segments[i];

if (typeof segment.start !== 'undefined') {
segmentSync = {
mediaSequence: playlist.mediaSequence + i,
time: segment.start
};
break;
}
}

return { expiredSync, segmentSync };
};

/**
* Calculates the amount of time expired from the playlist based on the provided
* sync points.
*
* @param {Object} playlist a media playlist object
* @param {Object|null} expiredSync sync point representing most recent segment with
* timing sync data that has fallen off the playlist
* @param {Object|null} segmentSync sync point representing the first segment that has
* timing sync data in the playlist
* @returns {Number} the amount of time expired from the playlist
* @function calculateExpiredTime
*/
const calculateExpiredTime = function(playlist) {
// If we have both an expired sync point and a segment sync point
// determine which sync point is closest to the start of the playlist
// so the minimal amount of timing estimation is done.
let { expiredSync, segmentSync } = getPlaylistSyncPoints(playlist);

if (expiredSync && segmentSync) {
let expiredDiff = expiredSync.mediaSequence - playlist.mediaSequence;
let segmentDiff = segmentSync.mediaSequence - playlist.mediaSequence;
let syncIndex;
let syncTime;

if (Math.abs(expiredDiff) > Math.abs(segmentDiff)) {
syncIndex = segmentDiff;
syncTime = -segmentSync.time;
} else {
syncIndex = expiredDiff;
syncTime = expiredSync.time;
}

return Math.abs(syncTime + sumDurations(playlist, syncIndex, 0));
}

// We only have an expired sync point, so base expired time on the expired sync point
// and estimate the time from that sync point to the start of the playlist.
if (expiredSync) {
let syncIndex = expiredSync.mediaSequence - playlist.mediaSequence;

return expiredSync.time + sumDurations(playlist, syncIndex, 0);
}

// We only have a segment sync point, so base expired time on the first segment we have
// sync point data for and estimate the time from that media index to the start of the
// playlist.
if (segmentSync) {
let syncIndex = segmentSync.mediaSequence - playlist.mediaSequence;

return segmentSync.time - sumDurations(playlist, syncIndex, 0);
}
return null;
};

/**
* Calculates the playlist end time
*
* @param {Object} playlist a media playlist object
* @param {Number=} expired the amount of time that has
* dropped off the front of the playlist in a live scenario
* @param {Boolean|false} useSafeLiveEnd a boolean value indicating whether or not the playlist
* end calculation should consider the safe live end (truncate the playlist
* end by three segments). This is normally used for calculating the end of
* the playlist's seekable range.
* @returns {Number} the end time of playlist
* @function playlistEnd
*/
export const playlistEnd = function(playlist, useSafeLiveEnd) {
export const playlistEnd = function(playlist, expired, useSafeLiveEnd) {
if (!playlist || !playlist.segments) {
return null;
}
if (playlist.endList) {
return duration(playlist);
}
let expired = calculateExpiredTime(playlist);

if (expired === null) {
return null;
}

expired = expired || 0;

let endSequence = useSafeLiveEnd ? Math.max(0, playlist.segments.length - Playlist.UNSAFE_LIVE_SEGMENTS) :
Math.max(0, playlist.segments.length);

Expand All @@ -349,13 +264,15 @@ export const playlistEnd = function(playlist, useSafeLiveEnd) {
*
* @param {Object} playlist a media playlist object
* dropped off the front of the playlist in a live scenario
* @param {Number=} expired the amount of time that has
* dropped off the front of the playlist in a live scenario
* @return {TimeRanges} the periods of time that are valid targets
* for seeking
*/
export const seekable = function(playlist) {
export const seekable = function(playlist, expired) {
let useSafeLiveEnd = true;
let seekableStart = calculateExpiredTime(playlist);
let seekableEnd = playlistEnd(playlist, useSafeLiveEnd);
let seekableStart = expired || 0;
let seekableEnd = playlistEnd(playlist, expired, useSafeLiveEnd);

if (seekableEnd === null) {
return createTimeRange();
Expand Down
Loading

0 comments on commit 016d82f

Please sign in to comment.