28f9a7e4 by David LaPalomento

Don't assume media sequence starts at zero

Zero is the default when unspecified but it's legal to have a one-indexed VOD media playlist. When the media sequence is non-zero, assume that should be the basis for all sequence calculations unless a different basis was explicitly specified. Fix Playlist.seekable so that it doesn't attempt to estimate the duration of expired segments.
1 parent f7ecdae6
......@@ -149,8 +149,12 @@
intervalDuration = function(playlist, startSequence, endSequence, includeTrailingTime) {
var result = 0, targetDuration, expiredSegmentCount;
startSequence = startSequence || 0;
endSequence = endSequence !== undefined ? endSequence : (playlist.segments || []).length;
if (startSequence === undefined) {
startSequence = playlist.mediaSequence || 0;
}
if (endSequence === undefined) {
endSequence = startSequence + (playlist.segments || []).length;
}
targetDuration = playlist.targetDuration || DEFAULT_TARGET_DURATION;
// estimate expired segment duration using the target duration
......@@ -214,7 +218,11 @@
/**
* Calculates the interval of time that is currently seekable in a
* playlist.
* playlist. The returned time ranges are relative to the earliest
* moment in the specified playlist that is still available. A full
* seekable implementation for live streams would need to offset
* these values by the duration of content that has expired from the
* stream.
* @param playlist {object} a media playlist object
* @return {TimeRanges} the periods of time that are valid targets
* for seeking
......@@ -231,8 +239,8 @@
return videojs.createTimeRange(0, duration(playlist));
}
start = intervalDuration(playlist, 0, playlist.mediaSequence);
end = start + intervalDuration(playlist,
start = 0;
end = intervalDuration(playlist,
playlist.mediaSequence,
playlist.mediaSequence + playlist.segments.length);
targetDuration = playlist.targetDuration || DEFAULT_TARGET_DURATION;
......@@ -249,9 +257,9 @@
// from the result.
for (i = playlist.segments.length - 1; i >= 0 && liveBuffer > 0; i--) {
segment = playlist.segments[i];
pending = Math.min(segment.preciseDuration ||
segment.duration ||
targetDuration,
pending = Math.min(duration(playlist,
playlist.mediaSequence + i,
playlist.mediaSequence + i + 1),
liveBuffer);
liveBuffer -= pending;
end -= pending;
......
......@@ -423,7 +423,7 @@ videojs.Hls.prototype.duration = function() {
};
videojs.Hls.prototype.seekable = function() {
var absoluteSeekable, startOffset, media;
var currentSeekable, startOffset, media;
if (!this.playlists) {
return videojs.createTimeRange();
......@@ -435,10 +435,10 @@ videojs.Hls.prototype.seekable = function() {
// report the seekable range relative to the earliest possible
// position when the stream was first loaded
absoluteSeekable = videojs.Hls.Playlist.seekable(media);
currentSeekable = videojs.Hls.Playlist.seekable(media);
startOffset = this.playlists.expiredPostDiscontinuity_ - this.playlists.expiredPreDiscontinuity_;
return videojs.createTimeRange(startOffset,
startOffset + (absoluteSeekable.end(0) - absoluteSeekable.start(0)));
startOffset + (currentSeekable.end(0) - currentSeekable.start(0)));
};
/**
......
......@@ -18,10 +18,9 @@
module('Playlist Interval Duration');
test('accounts for media sequences', function() {
test('accounts expired duration for live playlists', function() {
var duration = Playlist.duration({
mediaSequence: 10,
endList: true,
segments: [{
duration: 10,
uri: '10.ts'
......@@ -40,6 +39,28 @@
equal(duration, 14 * 10, 'duration includes dropped segments');
});
test('accounts for non-zero starting VOD media sequences', function() {
var duration = Playlist.duration({
mediaSequence: 10,
endList: true,
segments: [{
duration: 10,
uri: '0.ts'
}, {
duration: 10,
uri: '1.ts'
}, {
duration: 10,
uri: '2.ts'
}, {
duration: 10,
uri: '3.ts'
}]
});
equal(duration, 4 * 10, 'includes only listed segments');
});
test('uses PTS values when available', function() {
var duration = Playlist.duration({
mediaSequence: 0,
......@@ -445,7 +466,7 @@
equal(seekable.end(0), 7, 'ends three target durations from the last segment');
});
test('adjusts seekable to the live playlist window', function() {
test('only considers available segments', function() {
var seekable = Playlist.seekable({
targetDuration: 10,
mediaSequence: 7,
......@@ -460,8 +481,8 @@
}]
});
equal(seekable.length, 1, 'there are seekable ranges');
equal(seekable.start(0), 10 * 7, 'starts at the earliest available segment');
equal(seekable.end(0), 10 * 8, 'ends three target durations from the last available segment');
equal(seekable.start(0), 0, 'starts at the earliest available segment');
equal(seekable.end(0), 10, 'ends three target durations from the last available segment');
});
test('seekable end accounts for non-standard target durations', function() {
......