Merge pull request #432 from dmlap/drain-race
Don't append segments that have already been appended
Showing
5 changed files
with
81 additions
and
81 deletions
... | @@ -9,21 +9,8 @@ | ... | @@ -9,21 +9,8 @@ |
9 | <!-- video.js --> | 9 | <!-- video.js --> |
10 | <script src="node_modules/video.js/dist/video.js"></script> | 10 | <script src="node_modules/video.js/dist/video.js"></script> |
11 | 11 | ||
12 | <!-- transmuxing --> | ||
13 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/lib/stream.js"></script> | ||
14 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/flv-tag.js"></script> | ||
15 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/exp-golomb.js"></script> | ||
16 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/h264-extradata.js"></script> | ||
17 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/h264-stream.js"></script> | ||
18 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/aac-stream.js"></script> | ||
19 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/metadata-stream.js"></script> | ||
20 | <script src="node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/segment-parser.js"></script> | ||
21 | |||
22 | <!-- Media Sources plugin --> | 12 | <!-- Media Sources plugin --> |
23 | <script src="node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> | 13 | <script src="node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script> |
24 | <script> | ||
25 | videojs.MediaSource.webWorkerURI = 'node_modules/videojs-contrib-media-sources/src/transmuxer_worker.js'; | ||
26 | </script> | ||
27 | 14 | ||
28 | <!-- HLS plugin --> | 15 | <!-- HLS plugin --> |
29 | <script src="src/videojs-hls.js"></script> | 16 | <script src="src/videojs-hls.js"></script> | ... | ... |
... | @@ -44,11 +44,11 @@ | ... | @@ -44,11 +44,11 @@ |
44 | "karma-sauce-launcher": "~0.1.8", | 44 | "karma-sauce-launcher": "~0.1.8", |
45 | "qunitjs": "^1.18.0", | 45 | "qunitjs": "^1.18.0", |
46 | "sinon": "1.10.2", | 46 | "sinon": "1.10.2", |
47 | "video.js": "^5.1.0" | 47 | "video.js": "^5.2.1" |
48 | }, | 48 | }, |
49 | "dependencies": { | 49 | "dependencies": { |
50 | "pkcs7": "^0.2.2", | 50 | "pkcs7": "^0.2.2", |
51 | "videojs-contrib-media-sources": "^2.0.0", | 51 | "videojs-contrib-media-sources": "^2.4.0", |
52 | "videojs-swf": "^5.0.0" | 52 | "videojs-swf": "^5.0.0" |
53 | } | 53 | } |
54 | } | 54 | } | ... | ... |
... | @@ -23,7 +23,8 @@ keyFailed = function(key) { | ... | @@ -23,7 +23,8 @@ keyFailed = function(key) { |
23 | return key.retries && key.retries >= 2; | 23 | return key.retries && key.retries >= 2; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | videojs.Hls = videojs.extend(Component, { | 26 | videojs.Hls = {}; |
27 | videojs.HlsHandler = videojs.extend(Component, { | ||
27 | constructor: function(tech, options) { | 28 | constructor: function(tech, options) { |
28 | var self = this, _player; | 29 | var self = this, _player; |
29 | 30 | ||
... | @@ -110,7 +111,7 @@ videojs.HlsSourceHandler = function(mode) { | ... | @@ -110,7 +111,7 @@ videojs.HlsSourceHandler = function(mode) { |
110 | tech.trigger('loadstart'); | 111 | tech.trigger('loadstart'); |
111 | }, 1); | 112 | }, 1); |
112 | } | 113 | } |
113 | tech.hls = new videojs.Hls(tech, { | 114 | tech.hls = new videojs.HlsHandler(tech, { |
114 | source: source, | 115 | source: source, |
115 | mode: mode | 116 | mode: mode |
116 | }); | 117 | }); |
... | @@ -129,7 +130,7 @@ videojs.getComponent('Flash').registerSourceHandler(videojs.HlsSourceHandler('fl | ... | @@ -129,7 +130,7 @@ videojs.getComponent('Flash').registerSourceHandler(videojs.HlsSourceHandler('fl |
129 | // the desired length of video to maintain in the buffer, in seconds | 130 | // the desired length of video to maintain in the buffer, in seconds |
130 | videojs.Hls.GOAL_BUFFER_LENGTH = 30; | 131 | videojs.Hls.GOAL_BUFFER_LENGTH = 30; |
131 | 132 | ||
132 | videojs.Hls.prototype.src = function(src) { | 133 | videojs.HlsHandler.prototype.src = function(src) { |
133 | var oldMediaPlaylist; | 134 | var oldMediaPlaylist; |
134 | 135 | ||
135 | // do nothing if the src is falsey | 136 | // do nothing if the src is falsey |
... | @@ -208,7 +209,7 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -208,7 +209,7 @@ videojs.Hls.prototype.src = function(src) { |
208 | this.tech_.src(videojs.URL.createObjectURL(this.mediaSource)); | 209 | this.tech_.src(videojs.URL.createObjectURL(this.mediaSource)); |
209 | }; | 210 | }; |
210 | 211 | ||
211 | videojs.Hls.prototype.handleSourceOpen = function() { | 212 | videojs.HlsHandler.prototype.handleSourceOpen = function() { |
212 | // Only attempt to create the source buffer if none already exist. | 213 | // Only attempt to create the source buffer if none already exist. |
213 | // handleSourceOpen is also called when we are "re-opening" a source buffer | 214 | // handleSourceOpen is also called when we are "re-opening" a source buffer |
214 | // after `endOfStream` has been called (in response to a seek for instance) | 215 | // after `endOfStream` has been called (in response to a seek for instance) |
... | @@ -284,7 +285,7 @@ videojs.Hls.bufferedAdditions_ = function(original, update) { | ... | @@ -284,7 +285,7 @@ videojs.Hls.bufferedAdditions_ = function(original, update) { |
284 | return result; | 285 | return result; |
285 | }; | 286 | }; |
286 | 287 | ||
287 | videojs.Hls.prototype.setupSourceBuffer_ = function() { | 288 | videojs.HlsHandler.prototype.setupSourceBuffer_ = function() { |
288 | var media = this.playlists.media(), mimeType; | 289 | var media = this.playlists.media(), mimeType; |
289 | 290 | ||
290 | // wait until a media playlist is available and the Media Source is | 291 | // wait until a media playlist is available and the Media Source is |
... | @@ -375,7 +376,7 @@ videojs.Hls.prototype.setupSourceBuffer_ = function() { | ... | @@ -375,7 +376,7 @@ videojs.Hls.prototype.setupSourceBuffer_ = function() { |
375 | * Seek to the latest media position if this is a live video and the | 376 | * Seek to the latest media position if this is a live video and the |
376 | * player and video are loaded and initialized. | 377 | * player and video are loaded and initialized. |
377 | */ | 378 | */ |
378 | videojs.Hls.prototype.setupFirstPlay = function() { | 379 | videojs.HlsHandler.prototype.setupFirstPlay = function() { |
379 | var seekable, media; | 380 | var seekable, media; |
380 | media = this.playlists.media(); | 381 | media = this.playlists.media(); |
381 | 382 | ||
... | @@ -405,7 +406,7 @@ videojs.Hls.prototype.setupFirstPlay = function() { | ... | @@ -405,7 +406,7 @@ videojs.Hls.prototype.setupFirstPlay = function() { |
405 | /** | 406 | /** |
406 | * Begin playing the video. | 407 | * Begin playing the video. |
407 | */ | 408 | */ |
408 | videojs.Hls.prototype.play = function() { | 409 | videojs.HlsHandler.prototype.play = function() { |
409 | this.loadingState_ = 'segments'; | 410 | this.loadingState_ = 'segments'; |
410 | 411 | ||
411 | if (this.tech_.ended()) { | 412 | if (this.tech_.ended()) { |
... | @@ -425,7 +426,7 @@ videojs.Hls.prototype.play = function() { | ... | @@ -425,7 +426,7 @@ videojs.Hls.prototype.play = function() { |
425 | } | 426 | } |
426 | }; | 427 | }; |
427 | 428 | ||
428 | videojs.Hls.prototype.setCurrentTime = function(currentTime) { | 429 | videojs.HlsHandler.prototype.setCurrentTime = function(currentTime) { |
429 | var | 430 | var |
430 | buffered = this.findCurrentBuffered_(); | 431 | buffered = this.findCurrentBuffered_(); |
431 | 432 | ||
... | @@ -461,7 +462,7 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { | ... | @@ -461,7 +462,7 @@ videojs.Hls.prototype.setCurrentTime = function(currentTime) { |
461 | this.fillBuffer(this.playlists.getMediaIndexForTime_(currentTime)); | 462 | this.fillBuffer(this.playlists.getMediaIndexForTime_(currentTime)); |
462 | }; | 463 | }; |
463 | 464 | ||
464 | videojs.Hls.prototype.duration = function() { | 465 | videojs.HlsHandler.prototype.duration = function() { |
465 | var playlists = this.playlists; | 466 | var playlists = this.playlists; |
466 | if (playlists) { | 467 | if (playlists) { |
467 | return videojs.Hls.Playlist.duration(playlists.media()); | 468 | return videojs.Hls.Playlist.duration(playlists.media()); |
... | @@ -469,7 +470,7 @@ videojs.Hls.prototype.duration = function() { | ... | @@ -469,7 +470,7 @@ videojs.Hls.prototype.duration = function() { |
469 | return 0; | 470 | return 0; |
470 | }; | 471 | }; |
471 | 472 | ||
472 | videojs.Hls.prototype.seekable = function() { | 473 | videojs.HlsHandler.prototype.seekable = function() { |
473 | var media; | 474 | var media; |
474 | 475 | ||
475 | if (!this.playlists) { | 476 | if (!this.playlists) { |
... | @@ -486,31 +487,32 @@ videojs.Hls.prototype.seekable = function() { | ... | @@ -486,31 +487,32 @@ videojs.Hls.prototype.seekable = function() { |
486 | /** | 487 | /** |
487 | * Update the player duration | 488 | * Update the player duration |
488 | */ | 489 | */ |
489 | videojs.Hls.prototype.updateDuration = function(playlist) { | 490 | videojs.HlsHandler.prototype.updateDuration = function(playlist) { |
490 | var oldDuration = this.mediaSource.duration, | 491 | var oldDuration = this.mediaSource.duration, |
491 | newDuration = videojs.Hls.Playlist.duration(playlist), | 492 | newDuration = videojs.Hls.Playlist.duration(playlist), |
492 | setDuration = function() { | 493 | setDuration = function() { |
493 | this.mediaSource.duration = newDuration; | 494 | this.mediaSource.duration = newDuration; |
495 | // update seekable | ||
496 | if (seekable.length !== 0 && newDuration === Infinity) { | ||
497 | this.mediaSource.addSeekableRange_(seekable.start(0), seekable.end(0)); | ||
498 | } | ||
494 | this.tech_.trigger('durationchange'); | 499 | this.tech_.trigger('durationchange'); |
500 | |||
495 | this.mediaSource.removeEventListener('sourceopen', setDuration); | 501 | this.mediaSource.removeEventListener('sourceopen', setDuration); |
496 | }.bind(this), | 502 | }.bind(this), |
497 | seekable = this.seekable(); | 503 | seekable = this.seekable(); |
498 | 504 | ||
499 | // TODO: Move to videojs-contrib-media-sources | ||
500 | if (seekable.length && newDuration === Infinity) { | ||
501 | if (isNaN(oldDuration)) { | ||
502 | oldDuration = 0; | ||
503 | } | ||
504 | newDuration = Math.max(oldDuration, | ||
505 | seekable.end(0) + playlist.targetDuration * 3); | ||
506 | } | ||
507 | |||
508 | // if the duration has changed, invalidate the cached value | 505 | // if the duration has changed, invalidate the cached value |
509 | if (oldDuration !== newDuration) { | 506 | if (oldDuration !== newDuration) { |
507 | // update the duration | ||
510 | if (this.mediaSource.readyState !== 'open') { | 508 | if (this.mediaSource.readyState !== 'open') { |
511 | this.mediaSource.addEventListener('sourceopen', setDuration); | 509 | this.mediaSource.addEventListener('sourceopen', setDuration); |
512 | } else if (!this.sourceBuffer || !this.sourceBuffer.updating) { | 510 | } else if (!this.sourceBuffer || !this.sourceBuffer.updating) { |
513 | this.mediaSource.duration = newDuration; | 511 | this.mediaSource.duration = newDuration; |
512 | // update seekable | ||
513 | if (seekable.length !== 0 && newDuration === Infinity) { | ||
514 | this.mediaSource.addSeekableRange_(seekable.start(0), seekable.end(0)); | ||
515 | } | ||
514 | this.tech_.trigger('durationchange'); | 516 | this.tech_.trigger('durationchange'); |
515 | } | 517 | } |
516 | } | 518 | } |
... | @@ -521,7 +523,7 @@ videojs.Hls.prototype.updateDuration = function(playlist) { | ... | @@ -521,7 +523,7 @@ videojs.Hls.prototype.updateDuration = function(playlist) { |
521 | * source. After this function is called, the tech should be in a | 523 | * source. After this function is called, the tech should be in a |
522 | * state suitable for switching to a different video. | 524 | * state suitable for switching to a different video. |
523 | */ | 525 | */ |
524 | videojs.Hls.prototype.resetSrc_ = function() { | 526 | videojs.HlsHandler.prototype.resetSrc_ = function() { |
525 | this.cancelSegmentXhr(); | 527 | this.cancelSegmentXhr(); |
526 | this.cancelKeyXhr(); | 528 | this.cancelKeyXhr(); |
527 | 529 | ||
... | @@ -530,7 +532,7 @@ videojs.Hls.prototype.resetSrc_ = function() { | ... | @@ -530,7 +532,7 @@ videojs.Hls.prototype.resetSrc_ = function() { |
530 | } | 532 | } |
531 | }; | 533 | }; |
532 | 534 | ||
533 | videojs.Hls.prototype.cancelKeyXhr = function() { | 535 | videojs.HlsHandler.prototype.cancelKeyXhr = function() { |
534 | if (this.keyXhr_) { | 536 | if (this.keyXhr_) { |
535 | this.keyXhr_.onreadystatechange = null; | 537 | this.keyXhr_.onreadystatechange = null; |
536 | this.keyXhr_.abort(); | 538 | this.keyXhr_.abort(); |
... | @@ -538,7 +540,7 @@ videojs.Hls.prototype.cancelKeyXhr = function() { | ... | @@ -538,7 +540,7 @@ videojs.Hls.prototype.cancelKeyXhr = function() { |
538 | } | 540 | } |
539 | }; | 541 | }; |
540 | 542 | ||
541 | videojs.Hls.prototype.cancelSegmentXhr = function() { | 543 | videojs.HlsHandler.prototype.cancelSegmentXhr = function() { |
542 | if (this.segmentXhr_) { | 544 | if (this.segmentXhr_) { |
543 | // Prevent error handler from running. | 545 | // Prevent error handler from running. |
544 | this.segmentXhr_.onreadystatechange = null; | 546 | this.segmentXhr_.onreadystatechange = null; |
... | @@ -552,7 +554,7 @@ videojs.Hls.prototype.cancelSegmentXhr = function() { | ... | @@ -552,7 +554,7 @@ videojs.Hls.prototype.cancelSegmentXhr = function() { |
552 | /** | 554 | /** |
553 | * Abort all outstanding work and cleanup. | 555 | * Abort all outstanding work and cleanup. |
554 | */ | 556 | */ |
555 | videojs.Hls.prototype.dispose = function() { | 557 | videojs.HlsHandler.prototype.dispose = function() { |
556 | this.stopCheckingBuffer_(); | 558 | this.stopCheckingBuffer_(); |
557 | 559 | ||
558 | if (this.playlists) { | 560 | if (this.playlists) { |
... | @@ -569,7 +571,7 @@ videojs.Hls.prototype.dispose = function() { | ... | @@ -569,7 +571,7 @@ videojs.Hls.prototype.dispose = function() { |
569 | * @return the highest bitrate playlist less than the currently detected | 571 | * @return the highest bitrate playlist less than the currently detected |
570 | * bandwidth, accounting for some amount of bandwidth variance | 572 | * bandwidth, accounting for some amount of bandwidth variance |
571 | */ | 573 | */ |
572 | videojs.Hls.prototype.selectPlaylist = function () { | 574 | videojs.HlsHandler.prototype.selectPlaylist = function () { |
573 | var | 575 | var |
574 | effectiveBitrate, | 576 | effectiveBitrate, |
575 | sortedPlaylists = this.playlists.master.playlists.slice(), | 577 | sortedPlaylists = this.playlists.master.playlists.slice(), |
... | @@ -662,7 +664,7 @@ videojs.Hls.prototype.selectPlaylist = function () { | ... | @@ -662,7 +664,7 @@ videojs.Hls.prototype.selectPlaylist = function () { |
662 | /** | 664 | /** |
663 | * Periodically request new segments and append video data. | 665 | * Periodically request new segments and append video data. |
664 | */ | 666 | */ |
665 | videojs.Hls.prototype.checkBuffer_ = function() { | 667 | videojs.HlsHandler.prototype.checkBuffer_ = function() { |
666 | // calling this method directly resets any outstanding buffer checks | 668 | // calling this method directly resets any outstanding buffer checks |
667 | if (this.checkBufferTimeout_) { | 669 | if (this.checkBufferTimeout_) { |
668 | window.clearTimeout(this.checkBufferTimeout_); | 670 | window.clearTimeout(this.checkBufferTimeout_); |
... | @@ -681,7 +683,7 @@ videojs.Hls.prototype.checkBuffer_ = function() { | ... | @@ -681,7 +683,7 @@ videojs.Hls.prototype.checkBuffer_ = function() { |
681 | * Setup a periodic task to request new segments if necessary and | 683 | * Setup a periodic task to request new segments if necessary and |
682 | * append bytes into the SourceBuffer. | 684 | * append bytes into the SourceBuffer. |
683 | */ | 685 | */ |
684 | videojs.Hls.prototype.startCheckingBuffer_ = function() { | 686 | videojs.HlsHandler.prototype.startCheckingBuffer_ = function() { |
685 | // if the player ever stalls, check if there is video data available | 687 | // if the player ever stalls, check if there is video data available |
686 | // to append immediately | 688 | // to append immediately |
687 | this.tech_.on('waiting', (this.drainBuffer).bind(this)); | 689 | this.tech_.on('waiting', (this.drainBuffer).bind(this)); |
... | @@ -693,7 +695,7 @@ videojs.Hls.prototype.startCheckingBuffer_ = function() { | ... | @@ -693,7 +695,7 @@ videojs.Hls.prototype.startCheckingBuffer_ = function() { |
693 | * Stop the periodic task requesting new segments and feeding the | 695 | * Stop the periodic task requesting new segments and feeding the |
694 | * SourceBuffer. | 696 | * SourceBuffer. |
695 | */ | 697 | */ |
696 | videojs.Hls.prototype.stopCheckingBuffer_ = function() { | 698 | videojs.HlsHandler.prototype.stopCheckingBuffer_ = function() { |
697 | if (this.checkBufferTimeout_) { | 699 | if (this.checkBufferTimeout_) { |
698 | window.clearTimeout(this.checkBufferTimeout_); | 700 | window.clearTimeout(this.checkBufferTimeout_); |
699 | this.checkBufferTimeout_ = null; | 701 | this.checkBufferTimeout_ = null; |
... | @@ -705,7 +707,7 @@ videojs.Hls.prototype.stopCheckingBuffer_ = function() { | ... | @@ -705,7 +707,7 @@ videojs.Hls.prototype.stopCheckingBuffer_ = function() { |
705 | * Attempts to find the buffered TimeRange where playback is currently | 707 | * Attempts to find the buffered TimeRange where playback is currently |
706 | * happening. Returns a new TimeRange with one or zero ranges. | 708 | * happening. Returns a new TimeRange with one or zero ranges. |
707 | */ | 709 | */ |
708 | videojs.Hls.prototype.findCurrentBuffered_ = function() { | 710 | videojs.HlsHandler.prototype.findCurrentBuffered_ = function() { |
709 | var | 711 | var |
710 | ranges, | 712 | ranges, |
711 | i, | 713 | i, |
... | @@ -743,7 +745,7 @@ videojs.Hls.prototype.findCurrentBuffered_ = function() { | ... | @@ -743,7 +745,7 @@ videojs.Hls.prototype.findCurrentBuffered_ = function() { |
743 | * @param seekToTime (optional) {number} the offset into the downloaded segment | 745 | * @param seekToTime (optional) {number} the offset into the downloaded segment |
744 | * to seek to, in seconds | 746 | * to seek to, in seconds |
745 | */ | 747 | */ |
746 | videojs.Hls.prototype.fillBuffer = function(mediaIndex) { | 748 | videojs.HlsHandler.prototype.fillBuffer = function(mediaIndex) { |
747 | var | 749 | var |
748 | tech = this.tech_, | 750 | tech = this.tech_, |
749 | currentTime = tech.currentTime(), | 751 | currentTime = tech.currentTime(), |
... | @@ -840,7 +842,7 @@ videojs.Hls.prototype.fillBuffer = function(mediaIndex) { | ... | @@ -840,7 +842,7 @@ videojs.Hls.prototype.fillBuffer = function(mediaIndex) { |
840 | this.loadSegment(segmentInfo); | 842 | this.loadSegment(segmentInfo); |
841 | }; | 843 | }; |
842 | 844 | ||
843 | videojs.Hls.prototype.playlistUriToUrl = function(segmentRelativeUrl) { | 845 | videojs.HlsHandler.prototype.playlistUriToUrl = function(segmentRelativeUrl) { |
844 | var playListUrl; | 846 | var playListUrl; |
845 | // resolve the segment URL relative to the playlist | 847 | // resolve the segment URL relative to the playlist |
846 | if (this.playlists.media().uri === this.source_.src) { | 848 | if (this.playlists.media().uri === this.source_.src) { |
... | @@ -859,7 +861,7 @@ videojs.Hls.prototype.playlistUriToUrl = function(segmentRelativeUrl) { | ... | @@ -859,7 +861,7 @@ videojs.Hls.prototype.playlistUriToUrl = function(segmentRelativeUrl) { |
859 | * * `bytesReceived` - amount of bytes downloaded | 861 | * * `bytesReceived` - amount of bytes downloaded |
860 | * `bandwidth` is the only required property. | 862 | * `bandwidth` is the only required property. |
861 | */ | 863 | */ |
862 | videojs.Hls.prototype.setBandwidth = function(xhr) { | 864 | videojs.HlsHandler.prototype.setBandwidth = function(xhr) { |
863 | // calculate the download bandwidth | 865 | // calculate the download bandwidth |
864 | this.segmentXhrTime = xhr.roundTripTime; | 866 | this.segmentXhrTime = xhr.roundTripTime; |
865 | this.bandwidth = xhr.bandwidth; | 867 | this.bandwidth = xhr.bandwidth; |
... | @@ -868,7 +870,7 @@ videojs.Hls.prototype.setBandwidth = function(xhr) { | ... | @@ -868,7 +870,7 @@ videojs.Hls.prototype.setBandwidth = function(xhr) { |
868 | this.tech_.trigger('bandwidthupdate'); | 870 | this.tech_.trigger('bandwidthupdate'); |
869 | }; | 871 | }; |
870 | 872 | ||
871 | videojs.Hls.prototype.loadSegment = function(segmentInfo) { | 873 | videojs.HlsHandler.prototype.loadSegment = function(segmentInfo) { |
872 | var | 874 | var |
873 | self = this, | 875 | self = this, |
874 | segment = segmentInfo.playlist.segments[segmentInfo.mediaIndex]; | 876 | segment = segmentInfo.playlist.segments[segmentInfo.mediaIndex]; |
... | @@ -927,7 +929,7 @@ videojs.Hls.prototype.loadSegment = function(segmentInfo) { | ... | @@ -927,7 +929,7 @@ videojs.Hls.prototype.loadSegment = function(segmentInfo) { |
927 | }); | 929 | }); |
928 | }; | 930 | }; |
929 | 931 | ||
930 | videojs.Hls.prototype.drainBuffer = function(event) { | 932 | videojs.HlsHandler.prototype.drainBuffer = function(event) { |
931 | var | 933 | var |
932 | segmentInfo, | 934 | segmentInfo, |
933 | mediaIndex, | 935 | mediaIndex, |
... | @@ -948,6 +950,12 @@ videojs.Hls.prototype.drainBuffer = function(event) { | ... | @@ -948,6 +950,12 @@ videojs.Hls.prototype.drainBuffer = function(event) { |
948 | return; | 950 | return; |
949 | } | 951 | } |
950 | 952 | ||
953 | // the pending segment has already been appended and we're waiting | ||
954 | // for updateend to fire | ||
955 | if (this.pendingSegment_.buffered) { | ||
956 | return; | ||
957 | } | ||
958 | |||
951 | // we can't append more data if the source buffer is busy processing | 959 | // we can't append more data if the source buffer is busy processing |
952 | // what we've already sent | 960 | // what we've already sent |
953 | if (this.sourceBuffer.updating) { | 961 | if (this.sourceBuffer.updating) { |
... | @@ -1034,7 +1042,7 @@ videojs.Hls.prototype.drainBuffer = function(event) { | ... | @@ -1034,7 +1042,7 @@ videojs.Hls.prototype.drainBuffer = function(event) { |
1034 | /** | 1042 | /** |
1035 | * Attempt to retrieve the key for a particular media segment. | 1043 | * Attempt to retrieve the key for a particular media segment. |
1036 | */ | 1044 | */ |
1037 | videojs.Hls.prototype.fetchKey_ = function(segment) { | 1045 | videojs.HlsHandler.prototype.fetchKey_ = function(segment) { |
1038 | var key, self, settings, receiveKey; | 1046 | var key, self, settings, receiveKey; |
1039 | 1047 | ||
1040 | // if there is a pending XHR or no segments, don't do anything | 1048 | // if there is a pending XHR or no segments, don't do anything | ... | ... |
... | @@ -9,23 +9,9 @@ | ... | @@ -9,23 +9,9 @@ |
9 | <!-- video.js --> | 9 | <!-- video.js --> |
10 | <script src="../../node_modules/video.js/dist/video.js"></script> | 10 | <script src="../../node_modules/video.js/dist/video.js"></script> |
11 | 11 | ||
12 | <!-- transmuxing --> | ||
13 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/lib/stream.js"></script> | ||
14 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/lib/mp4-generator.js"></script> | ||
15 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/lib/transmuxer.js"></script> | ||
16 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/flv-tag.js"></script> | ||
17 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/exp-golomb.js"></script> | ||
18 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/h264-extradata.js"></script> | ||
19 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/h264-stream.js"></script> | ||
20 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/aac-stream.js"></script> | ||
21 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/metadata-stream.js"></script> | ||
22 | <script src="../../node_modules/videojs-contrib-media-sources/node_modules/mux.js/legacy/segment-parser.js"></script> | ||
23 | |||
24 | <!-- Media Sources plugin --> | 12 | <!-- Media Sources plugin --> |
25 | <script src="../../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> | 13 | <script src="../../node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script> |
26 | <script> | 14 | |
27 | videojs.MediaSource.webWorkerURI = '../../node_modules/videojs-contrib-media-sources/src/transmuxer_worker.js'; | ||
28 | </script> | ||
29 | <!-- HLS plugin --> | 15 | <!-- HLS plugin --> |
30 | <script src="../../src/videojs-hls.js"></script> | 16 | <script src="../../src/videojs-hls.js"></script> |
31 | 17 | ... | ... |
... | @@ -134,11 +134,6 @@ var | ... | @@ -134,11 +134,6 @@ var |
134 | type: 'sourceopen', | 134 | type: 'sourceopen', |
135 | swfId: player.tech_.el().id | 135 | swfId: player.tech_.el().id |
136 | }); | 136 | }); |
137 | |||
138 | // endOfStream triggers an exception if flash isn't available | ||
139 | player.tech_.hls.mediaSource.endOfStream = function(error) { | ||
140 | this.error_ = error; | ||
141 | }; | ||
142 | }, | 137 | }, |
143 | standardXHRResponse = function(request) { | 138 | standardXHRResponse = function(request) { |
144 | if (!request.url) { | 139 | if (!request.url) { |
... | @@ -170,6 +165,11 @@ var | ... | @@ -170,6 +165,11 @@ var |
170 | // a no-op MediaSource implementation to allow synchronous testing | 165 | // a no-op MediaSource implementation to allow synchronous testing |
171 | MockMediaSource = videojs.extend(videojs.EventTarget, { | 166 | MockMediaSource = videojs.extend(videojs.EventTarget, { |
172 | constructor: function() {}, | 167 | constructor: function() {}, |
168 | duration: NaN, | ||
169 | seekable: videojs.createTimeRange(), | ||
170 | addSeekableRange_: function(start, end) { | ||
171 | this.seekable = videojs.createTimeRange(start, end); | ||
172 | }, | ||
173 | addSourceBuffer: function() { | 173 | addSourceBuffer: function() { |
174 | return new (videojs.extend(videojs.EventTarget, { | 174 | return new (videojs.extend(videojs.EventTarget, { |
175 | constructor: function() {}, | 175 | constructor: function() {}, |
... | @@ -179,7 +179,10 @@ var | ... | @@ -179,7 +179,10 @@ var |
179 | remove: function() {} | 179 | remove: function() {} |
180 | }))(); | 180 | }))(); |
181 | }, | 181 | }, |
182 | endOfStream: function() {} | 182 | // endOfStream triggers an exception if flash isn't available |
183 | endOfStream: function(error) { | ||
184 | this.error_ = error; | ||
185 | } | ||
183 | }), | 186 | }), |
184 | 187 | ||
185 | // do a shallow copy of the properties of source onto the target object | 188 | // do a shallow copy of the properties of source onto the target object |
... | @@ -1180,16 +1183,24 @@ test('only makes one segment request at a time', function() { | ... | @@ -1180,16 +1183,24 @@ test('only makes one segment request at a time', function() { |
1180 | }); | 1183 | }); |
1181 | 1184 | ||
1182 | test('only appends one segment at a time', function() { | 1185 | test('only appends one segment at a time', function() { |
1186 | var appends = 0; | ||
1183 | player.src({ | 1187 | player.src({ |
1184 | src: 'manifest/media.m3u8', | 1188 | src: 'manifest/media.m3u8', |
1185 | type: 'application/vnd.apple.mpegurl' | 1189 | type: 'application/vnd.apple.mpegurl' |
1186 | }); | 1190 | }); |
1187 | openMediaSource(player); | 1191 | openMediaSource(player); |
1188 | standardXHRResponse(requests.pop()); // media.m3u8 | 1192 | standardXHRResponse(requests.pop()); // media.m3u8 |
1193 | player.tech_.hls.sourceBuffer.appendBuffer = function() { | ||
1194 | appends++; | ||
1195 | }; | ||
1196 | |||
1189 | standardXHRResponse(requests.pop()); // segment 0 | 1197 | standardXHRResponse(requests.pop()); // segment 0 |
1190 | 1198 | ||
1191 | player.tech_.hls.checkBuffer_(); | 1199 | player.tech_.hls.checkBuffer_(); |
1192 | equal(requests.length, 0, 'did not request while updating'); | 1200 | equal(requests.length, 0, 'did not request while updating'); |
1201 | |||
1202 | player.tech_.hls.checkBuffer_(); | ||
1203 | equal(appends, 1, 'appended once'); | ||
1193 | }); | 1204 | }); |
1194 | 1205 | ||
1195 | test('waits to download new segments until the media playlist is stable', function() { | 1206 | test('waits to download new segments until the media playlist is stable', function() { |
... | @@ -1377,7 +1388,7 @@ test('seeking in an empty playlist is a non-erroring noop', function() { | ... | @@ -1377,7 +1388,7 @@ test('seeking in an empty playlist is a non-erroring noop', function() { |
1377 | equal(requests.length, requestsLength, 'made no additional requests'); | 1388 | equal(requests.length, requestsLength, 'made no additional requests'); |
1378 | }); | 1389 | }); |
1379 | 1390 | ||
1380 | test('tech\'s duration reports Infinity for live playlists', function() { | 1391 | test('sets seekable and duration for live playlists', function() { |
1381 | player.src({ | 1392 | player.src({ |
1382 | src: 'http://example.com/manifest/missingEndlist.m3u8', | 1393 | src: 'http://example.com/manifest/missingEndlist.m3u8', |
1383 | type: 'application/vnd.apple.mpegurl' | 1394 | type: 'application/vnd.apple.mpegurl' |
... | @@ -1386,13 +1397,19 @@ test('tech\'s duration reports Infinity for live playlists', function() { | ... | @@ -1386,13 +1397,19 @@ test('tech\'s duration reports Infinity for live playlists', function() { |
1386 | 1397 | ||
1387 | standardXHRResponse(requests[0]); | 1398 | standardXHRResponse(requests[0]); |
1388 | 1399 | ||
1389 | strictEqual(player.tech_.duration(), | 1400 | equal(player.tech_.hls.mediaSource.seekable.length, |
1390 | Infinity, | 1401 | 1, |
1391 | 'duration on the tech is infinity'); | 1402 | 'set one seekable range'); |
1403 | equal(player.tech_.hls.mediaSource.seekable.start(0), | ||
1404 | player.tech_.hls.seekable().start(0), | ||
1405 | 'set seekable start'); | ||
1406 | equal(player.tech_.hls.mediaSource.seekable.end(0), | ||
1407 | player.tech_.hls.seekable().end(0), | ||
1408 | 'set seekable end'); | ||
1392 | 1409 | ||
1393 | notEqual(player.tech_.hls.mediaSource.duration, | 1410 | strictEqual(player.tech_.hls.mediaSource.duration, |
1394 | Infinity, | 1411 | Infinity, |
1395 | 'duration on the mediaSource is not infinity'); | 1412 | 'duration on the mediaSource is infinity'); |
1396 | }); | 1413 | }); |
1397 | 1414 | ||
1398 | test('live playlist starts three target durations before live', function() { | 1415 | test('live playlist starts three target durations before live', function() { |
... | @@ -1518,6 +1535,7 @@ test('reloads out-of-date live playlists when switching variants', function() { | ... | @@ -1518,6 +1535,7 @@ test('reloads out-of-date live playlists when switching variants', function() { |
1518 | }); | 1535 | }); |
1519 | 1536 | ||
1520 | test('if withCredentials global option is used, withCredentials is set on the XHR object', function() { | 1537 | test('if withCredentials global option is used, withCredentials is set on the XHR object', function() { |
1538 | var hlsOptions = videojs.options.hls; | ||
1521 | player.dispose(); | 1539 | player.dispose(); |
1522 | videojs.options.hls = { | 1540 | videojs.options.hls = { |
1523 | withCredentials: true | 1541 | withCredentials: true |
... | @@ -1530,6 +1548,7 @@ test('if withCredentials global option is used, withCredentials is set on the XH | ... | @@ -1530,6 +1548,7 @@ test('if withCredentials global option is used, withCredentials is set on the XH |
1530 | openMediaSource(player); | 1548 | openMediaSource(player); |
1531 | ok(requests[0].withCredentials, | 1549 | ok(requests[0].withCredentials, |
1532 | 'with credentials should be set to true if that option is passed in'); | 1550 | 'with credentials should be set to true if that option is passed in'); |
1551 | videojs.options.hls = hlsOptions; | ||
1533 | }); | 1552 | }); |
1534 | 1553 | ||
1535 | test('if withCredentials src option is used, withCredentials is set on the XHR object', function() { | 1554 | test('if withCredentials src option is used, withCredentials is set on the XHR object', function() { |
... | @@ -1901,10 +1920,10 @@ test('the source handler supports HLS mime types', function() { | ... | @@ -1901,10 +1920,10 @@ test('the source handler supports HLS mime types', function() { |
1901 | 1920 | ||
1902 | ok(!(videojs.HlsSourceHandler(techName).canHandleSource({ | 1921 | ok(!(videojs.HlsSourceHandler(techName).canHandleSource({ |
1903 | type: 'video/mp4' | 1922 | type: 'video/mp4' |
1904 | }) instanceof videojs.Hls), 'does not support mp4'); | 1923 | }) instanceof videojs.HlsHandler), 'does not support mp4'); |
1905 | ok(!(videojs.HlsSourceHandler(techName).canHandleSource({ | 1924 | ok(!(videojs.HlsSourceHandler(techName).canHandleSource({ |
1906 | type: 'video/x-flv' | 1925 | type: 'video/x-flv' |
1907 | }) instanceof videojs.Hls), 'does not support flv'); | 1926 | }) instanceof videojs.HlsHandler), 'does not support flv'); |
1908 | }); | 1927 | }); |
1909 | }); | 1928 | }); |
1910 | 1929 | ... | ... |
-
Please register or sign in to post a comment