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.
Showing
3 changed files
with
47 additions
and
18 deletions
... | @@ -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() { | ... | ... |
-
Please register or sign in to post a comment