Clamp seeks to the seekable range. Closes #327
Showing
3 changed files
with
103 additions
and
5 deletions
... | @@ -3,6 +3,7 @@ CHANGELOG | ... | @@ -3,6 +3,7 @@ CHANGELOG |
3 | 3 | ||
4 | ## HEAD (Unreleased) | 4 | ## HEAD (Unreleased) |
5 | * @dmlap improved video duration calculation. ([view](https://github.com/videojs/videojs-contrib-hls/pull/321)) | 5 | * @dmlap improved video duration calculation. ([view](https://github.com/videojs/videojs-contrib-hls/pull/321)) |
6 | * Clamp seeks to the seekable range ([view](https://github.com/videojs/videojs-contrib-hls/pull/327)) | ||
6 | 7 | ||
7 | -------------------- | 8 | -------------------- |
8 | 9 | ... | ... |
... | @@ -321,12 +321,21 @@ videojs.Hls.prototype.play = function() { | ... | @@ -321,12 +321,21 @@ videojs.Hls.prototype.play = function() { |
321 | this.mediaIndex = 0; | 321 | this.mediaIndex = 0; |
322 | } | 322 | } |
323 | 323 | ||
324 | // seek to the latest safe point in the media timeline when first | 324 | // we may need to seek to begin playing safely for live playlists |
325 | // playing live streams | 325 | if (this.duration() === Infinity) { |
326 | if (this.duration() === Infinity && | 326 | |
327 | this.playlists.media() && | 327 | // if this is the first time we're playing the stream or we're |
328 | !this.player().hasClass('vjs-has-started')) { | 328 | // ahead of the latest safe playback position, seek to the live |
329 | // point | ||
330 | if (!this.player().hasClass('vjs-has-started') || | ||
331 | this.currentTime() > this.seekable().end(0)) { | ||
329 | this.setCurrentTime(this.seekable().end(0)); | 332 | this.setCurrentTime(this.seekable().end(0)); |
333 | |||
334 | } else if (this.currentTime() < this.seekable().start(0)) { | ||
335 | // if the viewer has paused and we fell out of the live window, | ||
336 | // seek forward to the earliest available position | ||
337 | this.setCurrentTime(this.seekable().start(0)); | ||
338 | } | ||
330 | } | 339 | } |
331 | 340 | ||
332 | // delegate back to the Flash implementation | 341 | // delegate back to the Flash implementation |
... | @@ -356,6 +365,13 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { | ... | @@ -356,6 +365,13 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { |
356 | return 0; | 365 | return 0; |
357 | } | 366 | } |
358 | 367 | ||
368 | // clamp seeks to the available seekable time range | ||
369 | if (currentTime < this.seekable().start(0)) { | ||
370 | currentTime = this.seekable().start(0); | ||
371 | } else if (currentTime > this.seekable().end(0)) { | ||
372 | currentTime = this.seekable().end(0); | ||
373 | } | ||
374 | |||
359 | // save the seek target so currentTime can report it correctly | 375 | // save the seek target so currentTime can report it correctly |
360 | // while the seek is pending | 376 | // while the seek is pending |
361 | this.lastSeekedTime_ = currentTime; | 377 | this.lastSeekedTime_ = currentTime; | ... | ... |
... | @@ -1686,6 +1686,87 @@ test('live playlist starts with correct currentTime value', function() { | ... | @@ -1686,6 +1686,87 @@ test('live playlist starts with correct currentTime value', function() { |
1686 | 'currentTime is updated at playback'); | 1686 | 'currentTime is updated at playback'); |
1687 | }); | 1687 | }); |
1688 | 1688 | ||
1689 | test('resets the time to a seekable position when resuming a live stream ' + | ||
1690 | 'after a long break', function() { | ||
1691 | var seekTarget; | ||
1692 | player.src({ | ||
1693 | src: 'live0.m3u8', | ||
1694 | type: 'application/vnd.apple.mpegurl' | ||
1695 | }); | ||
1696 | openMediaSource(player); | ||
1697 | requests.shift().respond(200, null, | ||
1698 | '#EXTM3U\n' + | ||
1699 | '#EXT-X-MEDIA-SEQUENCE:16\n' + | ||
1700 | '#EXTINF:10,\n' + | ||
1701 | '16.ts\n'); | ||
1702 | // mock out the player to simulate a live stream that has been | ||
1703 | // playing for awhile | ||
1704 | player.addClass('vjs-has-started'); | ||
1705 | player.hls.seekable = function() { | ||
1706 | return { | ||
1707 | start: function() { | ||
1708 | return 160; | ||
1709 | }, | ||
1710 | end: function() { | ||
1711 | return 170; | ||
1712 | } | ||
1713 | }; | ||
1714 | }; | ||
1715 | player.hls.currentTime = function() { | ||
1716 | return 0; | ||
1717 | }; | ||
1718 | player.hls.setCurrentTime = function(time) { | ||
1719 | if (time !== undefined) { | ||
1720 | seekTarget = time; | ||
1721 | } | ||
1722 | }; | ||
1723 | |||
1724 | player.play(); | ||
1725 | equal(seekTarget, player.seekable().start(0), 'seeked to the start of seekable'); | ||
1726 | |||
1727 | player.hls.currentTime = function() { | ||
1728 | return 180; | ||
1729 | }; | ||
1730 | player.play(); | ||
1731 | equal(seekTarget, player.seekable().end(0), 'seeked to the end of seekable'); | ||
1732 | }); | ||
1733 | |||
1734 | test('clamps seeks to the seekable window', function() { | ||
1735 | var seekTarget; | ||
1736 | player.src({ | ||
1737 | src: 'live0.m3u8', | ||
1738 | type: 'application/vnd.apple.mpegurl' | ||
1739 | }); | ||
1740 | openMediaSource(player); | ||
1741 | requests.shift().respond(200, null, | ||
1742 | '#EXTM3U\n' + | ||
1743 | '#EXT-X-MEDIA-SEQUENCE:16\n' + | ||
1744 | '#EXTINF:10,\n' + | ||
1745 | '16.ts\n'); | ||
1746 | // mock out a seekable window | ||
1747 | player.hls.seekable = function() { | ||
1748 | return { | ||
1749 | start: function() { | ||
1750 | return 160; | ||
1751 | }, | ||
1752 | end: function() { | ||
1753 | return 170; | ||
1754 | } | ||
1755 | }; | ||
1756 | }; | ||
1757 | player.hls.fillBuffer = function(time) { | ||
1758 | if (time !== undefined) { | ||
1759 | seekTarget = time; | ||
1760 | } | ||
1761 | }; | ||
1762 | |||
1763 | player.currentTime(180); | ||
1764 | equal(seekTarget * 0.001, player.seekable().end(0), 'forward seeks are clamped'); | ||
1765 | |||
1766 | player.currentTime(45); | ||
1767 | equal(seekTarget * 0.001, player.seekable().start(0), 'backward seeks are clamped'); | ||
1768 | }); | ||
1769 | |||
1689 | test('mediaIndex is zero before the first segment loads', function() { | 1770 | test('mediaIndex is zero before the first segment loads', function() { |
1690 | window.manifests['first-seg-load'] = | 1771 | window.manifests['first-seg-load'] = |
1691 | '#EXTM3U\n' + | 1772 | '#EXTM3U\n' + | ... | ... |
-
Please register or sign in to post a comment