Wait until the player is ready to set the source. Capture the target time during seeks.
Opening the media source before the player is fully initialized would result in loadstart happening too early and the big play button getting stuck over the player. The video element should report the desired currentTime while a seek is pending, so store this value when currentTime is set and return it until a seek completes successfully.
Showing
2 changed files
with
32 additions
and
13 deletions
... | @@ -183,21 +183,31 @@ var | ... | @@ -183,21 +183,31 @@ var |
183 | initSource = function(player, mediaSource, srcUrl) { | 183 | initSource = function(player, mediaSource, srcUrl) { |
184 | var | 184 | var |
185 | segmentParser = new videojs.Hls.SegmentParser(), | 185 | segmentParser = new videojs.Hls.SegmentParser(), |
186 | settings = videojs.util.mergeOptions({}, player.options().hls), | ||
186 | 187 | ||
188 | lastSeekedTime, | ||
187 | segmentXhr, | 189 | segmentXhr, |
188 | settings = videojs.util.mergeOptions({}, player.options().hls), | ||
189 | fillBuffer, | 190 | fillBuffer, |
190 | updateDuration; | 191 | updateDuration; |
191 | 192 | ||
192 | 193 | ||
193 | player.hls.currentTime = function(currentTime) { | 194 | player.hls.currentTime = function() { |
194 | if (currentTime === undefined) { | 195 | if (lastSeekedTime) { |
195 | return this.el().vjs_getProperty('currentTime'); | 196 | return lastSeekedTime; |
196 | } | 197 | } |
197 | 198 | return this.el().vjs_getProperty('currentTime'); | |
199 | }; | ||
200 | player.hls.setCurrentTime = function(currentTime) { | ||
198 | if (!(this.playlists && this.playlists.media())) { | 201 | if (!(this.playlists && this.playlists.media())) { |
202 | // return immediately if the metadata is not ready yet | ||
199 | return 0; | 203 | return 0; |
200 | } | 204 | } |
205 | |||
206 | // save the seek target so currentTime can report it correctly | ||
207 | // while the seek is pending | ||
208 | lastSeekedTime = currentTime; | ||
209 | |||
210 | // determine the requested segment | ||
201 | this.mediaIndex = | 211 | this.mediaIndex = |
202 | getMediaIndexByTime(this.playlists.media(), currentTime); | 212 | getMediaIndexByTime(this.playlists.media(), currentTime); |
203 | 213 | ||
... | @@ -330,8 +340,9 @@ var | ... | @@ -330,8 +340,9 @@ var |
330 | bufferedTime = player.buffered().end(0) - player.currentTime(); | 340 | bufferedTime = player.buffered().end(0) - player.currentTime(); |
331 | } | 341 | } |
332 | 342 | ||
333 | // if there is plenty of content in the buffer, relax for awhile | 343 | // if there is plenty of content in the buffer and we're not |
334 | if (bufferedTime >= goalBufferLength) { | 344 | // seeking, relax for awhile |
345 | if (typeof offset !== 'number' && bufferedTime >= goalBufferLength) { | ||
335 | return; | 346 | return; |
336 | } | 347 | } |
337 | 348 | ||
... | @@ -382,10 +393,15 @@ var | ... | @@ -382,10 +393,15 @@ var |
382 | // if we're refilling the buffer after a seek, scan through the muxed | 393 | // if we're refilling the buffer after a seek, scan through the muxed |
383 | // FLV tags until we find the one that is closest to the desired | 394 | // FLV tags until we find the one that is closest to the desired |
384 | // playback time | 395 | // playback time |
385 | if (offset !== undefined && typeof offset === "number") { | 396 | if (typeof offset === 'number') { |
386 | while (segmentParser.getTags()[0].pts < offset) { | 397 | while (segmentParser.getTags()[0].pts < offset) { |
387 | segmentParser.getNextTag(); | 398 | segmentParser.getNextTag(); |
388 | } | 399 | } |
400 | |||
401 | // tell the SWF where we will be seeking to | ||
402 | player.hls.el().vjs_setProperty('currentTime', | ||
403 | segmentParser.getTags()[0].pts * 0.001); | ||
404 | lastSeekedTime = null; | ||
389 | } | 405 | } |
390 | 406 | ||
391 | while (segmentParser.tagsAvailable()) { | 407 | while (segmentParser.tagsAvailable()) { |
... | @@ -473,6 +489,7 @@ videojs.Hls = videojs.Flash.extend({ | ... | @@ -473,6 +489,7 @@ videojs.Hls = videojs.Flash.extend({ |
473 | videojs.Hls.prototype.src = function(src) { | 489 | videojs.Hls.prototype.src = function(src) { |
474 | var | 490 | var |
475 | player = this.player(), | 491 | player = this.player(), |
492 | self = this, | ||
476 | mediaSource, | 493 | mediaSource, |
477 | source; | 494 | source; |
478 | 495 | ||
... | @@ -484,8 +501,8 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -484,8 +501,8 @@ videojs.Hls.prototype.src = function(src) { |
484 | }; | 501 | }; |
485 | this.mediaSource = mediaSource; | 502 | this.mediaSource = mediaSource; |
486 | initSource(player, mediaSource, src); | 503 | initSource(player, mediaSource, src); |
487 | this.ready(function() { | 504 | this.player().ready(function() { |
488 | this.el().vjs_src(source.src); | 505 | self.el().vjs_src(source.src); |
489 | }); | 506 | }); |
490 | } | 507 | } |
491 | }; | 508 | }; | ... | ... |
... | @@ -49,6 +49,7 @@ var | ... | @@ -49,6 +49,7 @@ var |
49 | 49 | ||
50 | tech = player.el().querySelector('.vjs-tech'); | 50 | tech = player.el().querySelector('.vjs-tech'); |
51 | tech.vjs_getProperty = function() {}; | 51 | tech.vjs_getProperty = function() {}; |
52 | tech.vjs_setProperty = function() {}; | ||
52 | tech.vjs_src = function() {}; | 53 | tech.vjs_src = function() {}; |
53 | videojs.Flash.onReady(tech.id); | 54 | videojs.Flash.onReady(tech.id); |
54 | 55 | ||
... | @@ -654,6 +655,7 @@ test('does not download the next segment if the buffer is full', function() { | ... | @@ -654,6 +655,7 @@ test('does not download the next segment if the buffer is full', function() { |
654 | 655 | ||
655 | player.trigger('timeupdate'); | 656 | player.trigger('timeupdate'); |
656 | 657 | ||
658 | console.log(requests); | ||
657 | strictEqual(requests.length, 1, 'no segment request was made'); | 659 | strictEqual(requests.length, 1, 'no segment request was made'); |
658 | }); | 660 | }); |
659 | 661 | ||
... | @@ -754,7 +756,7 @@ test('cancels outstanding XHRs when seeking', function() { | ... | @@ -754,7 +756,7 @@ test('cancels outstanding XHRs when seeking', function() { |
754 | // trigger a segment download request | 756 | // trigger a segment download request |
755 | player.trigger('timeupdate'); | 757 | player.trigger('timeupdate'); |
756 | // attempt to seek while the download is in progress | 758 | // attempt to seek while the download is in progress |
757 | player.hls.currentTime(7); | 759 | player.currentTime(7); |
758 | 760 | ||
759 | ok(requests[1].aborted, 'XHR aborted'); | 761 | ok(requests[1].aborted, 'XHR aborted'); |
760 | strictEqual(requests.length, 3, 'opened new XHR'); | 762 | strictEqual(requests.length, 3, 'opened new XHR'); |
... | @@ -830,7 +832,7 @@ test('drops tags before the target timestamp when seeking', function() { | ... | @@ -830,7 +832,7 @@ test('drops tags before the target timestamp when seeking', function() { |
830 | bytes: i | 832 | bytes: i |
831 | }); | 833 | }); |
832 | } | 834 | } |
833 | player.hls.currentTime(7); | 835 | player.currentTime(7); |
834 | standardXHRResponse(requests[2]); | 836 | standardXHRResponse(requests[2]); |
835 | 837 | ||
836 | while (callbacks.length) { | 838 | while (callbacks.length) { |
... | @@ -876,7 +878,7 @@ test('clears pending buffer updates when seeking', function() { | ... | @@ -876,7 +878,7 @@ test('clears pending buffer updates when seeking', function() { |
876 | 878 | ||
877 | // seek to 7s | 879 | // seek to 7s |
878 | tags.push({ pts: 7000, bytes: 7 }); | 880 | tags.push({ pts: 7000, bytes: 7 }); |
879 | player.hls.currentTime(7); | 881 | player.currentTime(7); |
880 | standardXHRResponse(requests[2]); | 882 | standardXHRResponse(requests[2]); |
881 | 883 | ||
882 | while (callbacks.length) { | 884 | while (callbacks.length) { | ... | ... |
-
Please register or sign in to post a comment