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 @@ ...@@ -149,8 +149,12 @@
149 intervalDuration = function(playlist, startSequence, endSequence, includeTrailingTime) { 149 intervalDuration = function(playlist, startSequence, endSequence, includeTrailingTime) {
150 var result = 0, targetDuration, expiredSegmentCount; 150 var result = 0, targetDuration, expiredSegmentCount;
151 151
152 startSequence = startSequence || 0; 152 if (startSequence === undefined) {
153 endSequence = endSequence !== undefined ? endSequence : (playlist.segments || []).length; 153 startSequence = playlist.mediaSequence || 0;
154 }
155 if (endSequence === undefined) {
156 endSequence = startSequence + (playlist.segments || []).length;
157 }
154 targetDuration = playlist.targetDuration || DEFAULT_TARGET_DURATION; 158 targetDuration = playlist.targetDuration || DEFAULT_TARGET_DURATION;
155 159
156 // estimate expired segment duration using the target duration 160 // estimate expired segment duration using the target duration
...@@ -214,7 +218,11 @@ ...@@ -214,7 +218,11 @@
214 218
215 /** 219 /**
216 * Calculates the interval of time that is currently seekable in a 220 * Calculates the interval of time that is currently seekable in a
217 * playlist. 221 * playlist. The returned time ranges are relative to the earliest
222 * moment in the specified playlist that is still available. A full
223 * seekable implementation for live streams would need to offset
224 * these values by the duration of content that has expired from the
225 * stream.
218 * @param playlist {object} a media playlist object 226 * @param playlist {object} a media playlist object
219 * @return {TimeRanges} the periods of time that are valid targets 227 * @return {TimeRanges} the periods of time that are valid targets
220 * for seeking 228 * for seeking
...@@ -231,10 +239,10 @@ ...@@ -231,10 +239,10 @@
231 return videojs.createTimeRange(0, duration(playlist)); 239 return videojs.createTimeRange(0, duration(playlist));
232 } 240 }
233 241
234 start = intervalDuration(playlist, 0, playlist.mediaSequence); 242 start = 0;
235 end = start + intervalDuration(playlist, 243 end = intervalDuration(playlist,
236 playlist.mediaSequence, 244 playlist.mediaSequence,
237 playlist.mediaSequence + playlist.segments.length); 245 playlist.mediaSequence + playlist.segments.length);
238 targetDuration = playlist.targetDuration || DEFAULT_TARGET_DURATION; 246 targetDuration = playlist.targetDuration || DEFAULT_TARGET_DURATION;
239 247
240 // live playlists should not expose three segment durations worth 248 // live playlists should not expose three segment durations worth
...@@ -249,9 +257,9 @@ ...@@ -249,9 +257,9 @@
249 // from the result. 257 // from the result.
250 for (i = playlist.segments.length - 1; i >= 0 && liveBuffer > 0; i--) { 258 for (i = playlist.segments.length - 1; i >= 0 && liveBuffer > 0; i--) {
251 segment = playlist.segments[i]; 259 segment = playlist.segments[i];
252 pending = Math.min(segment.preciseDuration || 260 pending = Math.min(duration(playlist,
253 segment.duration || 261 playlist.mediaSequence + i,
254 targetDuration, 262 playlist.mediaSequence + i + 1),
255 liveBuffer); 263 liveBuffer);
256 liveBuffer -= pending; 264 liveBuffer -= pending;
257 end -= pending; 265 end -= pending;
......
...@@ -423,7 +423,7 @@ videojs.Hls.prototype.duration = function() { ...@@ -423,7 +423,7 @@ videojs.Hls.prototype.duration = function() {
423 }; 423 };
424 424
425 videojs.Hls.prototype.seekable = function() { 425 videojs.Hls.prototype.seekable = function() {
426 var absoluteSeekable, startOffset, media; 426 var currentSeekable, startOffset, media;
427 427
428 if (!this.playlists) { 428 if (!this.playlists) {
429 return videojs.createTimeRange(); 429 return videojs.createTimeRange();
...@@ -435,10 +435,10 @@ videojs.Hls.prototype.seekable = function() { ...@@ -435,10 +435,10 @@ videojs.Hls.prototype.seekable = function() {
435 435
436 // report the seekable range relative to the earliest possible 436 // report the seekable range relative to the earliest possible
437 // position when the stream was first loaded 437 // position when the stream was first loaded
438 absoluteSeekable = videojs.Hls.Playlist.seekable(media); 438 currentSeekable = videojs.Hls.Playlist.seekable(media);
439 startOffset = this.playlists.expiredPostDiscontinuity_ - this.playlists.expiredPreDiscontinuity_; 439 startOffset = this.playlists.expiredPostDiscontinuity_ - this.playlists.expiredPreDiscontinuity_;
440 return videojs.createTimeRange(startOffset, 440 return videojs.createTimeRange(startOffset,
441 startOffset + (absoluteSeekable.end(0) - absoluteSeekable.start(0))); 441 startOffset + (currentSeekable.end(0) - currentSeekable.start(0)));
442 }; 442 };
443 443
444 /** 444 /**
......
...@@ -18,10 +18,9 @@ ...@@ -18,10 +18,9 @@
18 18
19 module('Playlist Interval Duration'); 19 module('Playlist Interval Duration');
20 20
21 test('accounts for media sequences', function() { 21 test('accounts expired duration for live playlists', function() {
22 var duration = Playlist.duration({ 22 var duration = Playlist.duration({
23 mediaSequence: 10, 23 mediaSequence: 10,
24 endList: true,
25 segments: [{ 24 segments: [{
26 duration: 10, 25 duration: 10,
27 uri: '10.ts' 26 uri: '10.ts'
...@@ -40,6 +39,28 @@ ...@@ -40,6 +39,28 @@
40 equal(duration, 14 * 10, 'duration includes dropped segments'); 39 equal(duration, 14 * 10, 'duration includes dropped segments');
41 }); 40 });
42 41
42 test('accounts for non-zero starting VOD media sequences', function() {
43 var duration = Playlist.duration({
44 mediaSequence: 10,
45 endList: true,
46 segments: [{
47 duration: 10,
48 uri: '0.ts'
49 }, {
50 duration: 10,
51 uri: '1.ts'
52 }, {
53 duration: 10,
54 uri: '2.ts'
55 }, {
56 duration: 10,
57 uri: '3.ts'
58 }]
59 });
60
61 equal(duration, 4 * 10, 'includes only listed segments');
62 });
63
43 test('uses PTS values when available', function() { 64 test('uses PTS values when available', function() {
44 var duration = Playlist.duration({ 65 var duration = Playlist.duration({
45 mediaSequence: 0, 66 mediaSequence: 0,
...@@ -445,7 +466,7 @@ ...@@ -445,7 +466,7 @@
445 equal(seekable.end(0), 7, 'ends three target durations from the last segment'); 466 equal(seekable.end(0), 7, 'ends three target durations from the last segment');
446 }); 467 });
447 468
448 test('adjusts seekable to the live playlist window', function() { 469 test('only considers available segments', function() {
449 var seekable = Playlist.seekable({ 470 var seekable = Playlist.seekable({
450 targetDuration: 10, 471 targetDuration: 10,
451 mediaSequence: 7, 472 mediaSequence: 7,
...@@ -460,8 +481,8 @@ ...@@ -460,8 +481,8 @@
460 }] 481 }]
461 }); 482 });
462 equal(seekable.length, 1, 'there are seekable ranges'); 483 equal(seekable.length, 1, 'there are seekable ranges');
463 equal(seekable.start(0), 10 * 7, 'starts at the earliest available segment'); 484 equal(seekable.start(0), 0, 'starts at the earliest available segment');
464 equal(seekable.end(0), 10 * 8, 'ends three target durations from the last available segment'); 485 equal(seekable.end(0), 10, 'ends three target durations from the last available segment');
465 }); 486 });
466 487
467 test('seekable end accounts for non-standard target durations', function() { 488 test('seekable end accounts for non-standard target durations', function() {
......