Merge branch 'master' into withcredentials
Conflicts: test/videojs-hls_test.js
Showing
11 changed files
with
33 additions
and
138 deletions
... | @@ -24,7 +24,6 @@ module.exports = function(grunt) { | ... | @@ -24,7 +24,6 @@ module.exports = function(grunt) { |
24 | dist: { | 24 | dist: { |
25 | nonull: true, | 25 | nonull: true, |
26 | src: ['src/videojs-hls.js', | 26 | src: ['src/videojs-hls.js', |
27 | 'src/async-queue.js', | ||
28 | 'src/flv-tag.js', | 27 | 'src/flv-tag.js', |
29 | 'src/exp-golomb.js', | 28 | 'src/exp-golomb.js', |
30 | 'src/h264-stream.js', | 29 | 'src/h264-stream.js', | ... | ... |
1 | [](https://travis-ci.org/videojs/videojs-contrib-hls) | ||
2 | |||
3 | # video.js HLS Plugin | 1 | # video.js HLS Plugin |
4 | 2 | ||
5 | A video.js plugin that plays HLS video on platforms that don't support it but have Flash. | 3 | A video.js plugin that plays HLS video on platforms that don't support it but have Flash. |
6 | 4 | ||
5 | [](https://travis-ci.org/videojs/videojs-contrib-hls) | ||
6 | |||
7 | ## Getting Started | 7 | ## Getting Started |
8 | Download the [plugin](https://github.com/videojs/videojs-contrib-hls/releases). On your web page: | 8 | Download the [plugin](https://github.com/videojs/videojs-contrib-hls/releases). On your web page: |
9 | 9 | ... | ... |
... | @@ -10,11 +10,10 @@ | ... | @@ -10,11 +10,10 @@ |
10 | <script src="node_modules/video.js/dist/video-js/video.js"></script> | 10 | <script src="node_modules/video.js/dist/video-js/video.js"></script> |
11 | 11 | ||
12 | <!-- Media Sources plugin --> | 12 | <!-- Media Sources plugin --> |
13 | <script src="node_modules/videojs-contrib-media-sources/videojs-media-sources.js"></script> | 13 | <script src="node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> |
14 | 14 | ||
15 | <!-- HLS plugin --> | 15 | <!-- HLS plugin --> |
16 | <script src="src/videojs-hls.js"></script> | 16 | <script src="src/videojs-hls.js"></script> |
17 | <script src="src/async-queue.js"></script> | ||
18 | 17 | ||
19 | <!-- segment handling --> | 18 | <!-- segment handling --> |
20 | <script src="src/flv-tag.js"></script> | 19 | <script src="src/flv-tag.js"></script> | ... | ... |
1 | { | 1 | { |
2 | "name": "videojs-contrib-hls", | 2 | "name": "videojs-contrib-hls", |
3 | "version": "0.4.0", | 3 | "version": "0.4.1", |
4 | "engines": { | 4 | "engines": { |
5 | "node": ">= 0.10.12" | 5 | "node": ">= 0.10.12" |
6 | }, | 6 | }, |
... | @@ -41,6 +41,6 @@ | ... | @@ -41,6 +41,6 @@ |
41 | "video.js": "^4.5" | 41 | "video.js": "^4.5" |
42 | }, | 42 | }, |
43 | "dependencies": { | 43 | "dependencies": { |
44 | "videojs-contrib-media-sources": "git+https://github.com/videojs/videojs-contrib-media-sources.git" | 44 | "videojs-contrib-media-sources": "^0.2" |
45 | } | 45 | } |
46 | } | 46 | } | ... | ... |
src/async-queue.js
deleted
100644 → 0
1 | (function(window, videojs, undefined) { | ||
2 | 'use strict'; | ||
3 | /** | ||
4 | * A queue object that manages tasks that should be processed | ||
5 | * serially but asynchronously. Loosely adapted from | ||
6 | * https://github.com/caolan/async#queue. | ||
7 | * @param worker {function} the callback to invoke with each value | ||
8 | * pushed onto the queue | ||
9 | * @return {object} an object with an array of `tasks` that remain to | ||
10 | * be processed and function `push` to add new tasks | ||
11 | */ | ||
12 | videojs.hls.queue = function(worker) { | ||
13 | var | ||
14 | q = { | ||
15 | tasks: [], | ||
16 | running: false, | ||
17 | push: function(task) { | ||
18 | q.tasks.push(task); | ||
19 | if (!q.running) { | ||
20 | window.setTimeout(process, 0); | ||
21 | q.running = true; | ||
22 | } | ||
23 | } | ||
24 | }, | ||
25 | process = function() { | ||
26 | var task; | ||
27 | if (q.tasks.length) { | ||
28 | task = q.tasks.shift(); | ||
29 | worker.call(this, task); | ||
30 | window.setTimeout(process, 0); | ||
31 | } else { | ||
32 | q.running = false; | ||
33 | } | ||
34 | }; | ||
35 | return q; | ||
36 | }; | ||
37 | })(window, window.videojs); |
... | @@ -289,15 +289,6 @@ var | ... | @@ -289,15 +289,6 @@ var |
289 | mediaSource = new videojs.MediaSource(), | 289 | mediaSource = new videojs.MediaSource(), |
290 | segmentParser = new videojs.hls.SegmentParser(), | 290 | segmentParser = new videojs.hls.SegmentParser(), |
291 | player = this, | 291 | player = this, |
292 | |||
293 | // async queue of Uint8Arrays to be appended to the SourceBuffer | ||
294 | tags = videojs.hls.queue(function(tag) { | ||
295 | player.hls.sourceBuffer.appendBuffer(tag, player); | ||
296 | |||
297 | if (player.hls.mediaIndex === player.hls.media.segments.length) { | ||
298 | mediaSource.endOfStream(); | ||
299 | } | ||
300 | }), | ||
301 | srcUrl, | 292 | srcUrl, |
302 | 293 | ||
303 | playlistXhr, | 294 | playlistXhr, |
... | @@ -385,11 +376,13 @@ var | ... | @@ -385,11 +376,13 @@ var |
385 | var currentTime = player.currentTime(); | 376 | var currentTime = player.currentTime(); |
386 | player.hls.mediaIndex = getMediaIndexByTime(player.hls.media, currentTime); | 377 | player.hls.mediaIndex = getMediaIndexByTime(player.hls.media, currentTime); |
387 | 378 | ||
379 | // abort any segments still being decoded | ||
380 | player.hls.sourceBuffer.abort(); | ||
381 | |||
388 | // cancel outstanding requests and buffer appends | 382 | // cancel outstanding requests and buffer appends |
389 | if (segmentXhr) { | 383 | if (segmentXhr) { |
390 | segmentXhr.abort(); | 384 | segmentXhr.abort(); |
391 | } | 385 | } |
392 | tags.tasks = []; | ||
393 | 386 | ||
394 | // begin filling the buffer at the new position | 387 | // begin filling the buffer at the new position |
395 | fillBuffer(currentTime * 1000); | 388 | fillBuffer(currentTime * 1000); |
... | @@ -701,11 +694,18 @@ var | ... | @@ -701,11 +694,18 @@ var |
701 | // queue up the bytes to be appended to the SourceBuffer | 694 | // queue up the bytes to be appended to the SourceBuffer |
702 | // the queue gives control back to the browser between tags | 695 | // the queue gives control back to the browser between tags |
703 | // so that large segments don't cause a "hiccup" in playback | 696 | // so that large segments don't cause a "hiccup" in playback |
704 | tags.push(segmentParser.getNextTag().bytes); | 697 | |
698 | player.hls.sourceBuffer.appendBuffer(segmentParser.getNextTag().bytes, | ||
699 | player); | ||
700 | |||
705 | } | 701 | } |
706 | 702 | ||
707 | player.hls.mediaIndex++; | 703 | player.hls.mediaIndex++; |
708 | 704 | ||
705 | if (player.hls.mediaIndex === player.hls.media.segments.length) { | ||
706 | mediaSource.endOfStream(); | ||
707 | } | ||
708 | |||
709 | // figure out what stream the next segment should be downloaded from | 709 | // figure out what stream the next segment should be downloaded from |
710 | // with the updated bandwidth information | 710 | // with the updated bandwidth information |
711 | updateCurrentPlaylist(); | 711 | updateCurrentPlaylist(); | ... | ... |
test/async-queue_test.js
deleted
100644 → 0
1 | (function(window, queue, undefined) { | ||
2 | var | ||
3 | oldSetTimeout, | ||
4 | callbacks; | ||
5 | module('async queue', { | ||
6 | setup: function() { | ||
7 | oldSetTimeout = window.setTimeout; | ||
8 | callbacks = []; | ||
9 | window.setTimeout = function(callback) { | ||
10 | callbacks.push(callback); | ||
11 | }; | ||
12 | }, | ||
13 | teardown: function() { | ||
14 | window.setTimeout = oldSetTimeout; | ||
15 | } | ||
16 | }); | ||
17 | |||
18 | test('runs tasks asynchronously', function() { | ||
19 | var | ||
20 | run = false, | ||
21 | q = queue(function() { | ||
22 | run = true; | ||
23 | }); | ||
24 | q.push(1); | ||
25 | |||
26 | ok(!run, 'tasks are not run immediately'); | ||
27 | |||
28 | callbacks[0](); | ||
29 | ok(run, 'tasks are run asynchronously'); | ||
30 | }); | ||
31 | |||
32 | test('runs one task at a time', function() { | ||
33 | var q = queue(function() {}); | ||
34 | q.push(1); | ||
35 | q.push(2); | ||
36 | q.push(3); | ||
37 | q.push(4); | ||
38 | q.push(5); | ||
39 | |||
40 | strictEqual(q.tasks.length, 5, 'all tasks are queued'); | ||
41 | strictEqual(1, callbacks.length, 'one callback is registered'); | ||
42 | }); | ||
43 | |||
44 | test('tasks are scheduled until the queue is empty', function() { | ||
45 | var q = queue(function() {}); | ||
46 | q.push(1); | ||
47 | q.push(2); | ||
48 | |||
49 | callbacks.shift()(); | ||
50 | strictEqual(1, callbacks.length, 'the next task is scheduled'); | ||
51 | |||
52 | callbacks.shift()(); | ||
53 | strictEqual(1, callbacks.length, 'nothing is scheduled on an empty queue'); | ||
54 | }); | ||
55 | |||
56 | test('can be emptied at any time', function() { | ||
57 | var | ||
58 | runs = 0, | ||
59 | q = queue(function() { | ||
60 | runs++; | ||
61 | }); | ||
62 | q.push(1); | ||
63 | q.push(2); | ||
64 | |||
65 | callbacks.shift()(); | ||
66 | strictEqual(1, runs, 'task one is run'); | ||
67 | |||
68 | q.tasks = []; | ||
69 | callbacks.shift()(); | ||
70 | strictEqual(1, runs, 'the remaining tasks are cancelled'); | ||
71 | }); | ||
72 | })(window, window.videojs.hls.queue); |
... | @@ -40,7 +40,7 @@ module.exports = function(config) { | ... | @@ -40,7 +40,7 @@ module.exports = function(config) { |
40 | 40 | ||
41 | files: [ | 41 | files: [ |
42 | '../node_modules/video.js/dist/video-js/video.js', | 42 | '../node_modules/video.js/dist/video-js/video.js', |
43 | '../node_modules/videojs-contrib-media-sources/videojs-media-sources.js', | 43 | '../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js', |
44 | '../test/karma-qunit-shim.js', | 44 | '../test/karma-qunit-shim.js', |
45 | "../src/videojs-hls.js", | 45 | "../src/videojs-hls.js", |
46 | "../src/flv-tag.js", | 46 | "../src/flv-tag.js", | ... | ... |
... | @@ -35,7 +35,7 @@ module.exports = function(config) { | ... | @@ -35,7 +35,7 @@ module.exports = function(config) { |
35 | 35 | ||
36 | files: [ | 36 | files: [ |
37 | '../node_modules/video.js/dist/video-js/video.js', | 37 | '../node_modules/video.js/dist/video-js/video.js', |
38 | '../node_modules/videojs-contrib-media-sources/videojs-media-sources.js', | 38 | '../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js', |
39 | '../test/karma-qunit-shim.js', | 39 | '../test/karma-qunit-shim.js', |
40 | "../src/videojs-hls.js", | 40 | "../src/videojs-hls.js", |
41 | "../src/flv-tag.js", | 41 | "../src/flv-tag.js", |
... | @@ -93,4 +93,4 @@ module.exports = function(config) { | ... | @@ -93,4 +93,4 @@ module.exports = function(config) { |
93 | // If browser does not capture in given timeout [ms], kill it | 93 | // If browser does not capture in given timeout [ms], kill it |
94 | captureTimeout: 60000 | 94 | captureTimeout: 60000 |
95 | }); | 95 | }); |
96 | }; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
96 | }; | ... | ... |
... | @@ -37,9 +37,6 @@ | ... | @@ -37,9 +37,6 @@ |
37 | <script src="tsSegment-bc.js"></script> | 37 | <script src="tsSegment-bc.js"></script> |
38 | <script src="../src/bin-utils.js"></script> | 38 | <script src="../src/bin-utils.js"></script> |
39 | 39 | ||
40 | <!-- async queue --> | ||
41 | <script src="../src/async-queue.js"></script> | ||
42 | |||
43 | <!-- Test cases --> | 40 | <!-- Test cases --> |
44 | <script> | 41 | <script> |
45 | module('environment'); | 42 | module('environment'); |
... | @@ -54,7 +51,6 @@ | ... | @@ -54,7 +51,6 @@ |
54 | <script src="exp-golomb_test.js"></script> | 51 | <script src="exp-golomb_test.js"></script> |
55 | <script src="flv-tag_test.js"></script> | 52 | <script src="flv-tag_test.js"></script> |
56 | <script src="m3u8_test.js"></script> | 53 | <script src="m3u8_test.js"></script> |
57 | <script src="async-queue_test.js"></script> | ||
58 | </head> | 54 | </head> |
59 | <body> | 55 | <body> |
60 | <div id="qunit"></div> | 56 | <div id="qunit"></div> | ... | ... |
... | @@ -91,6 +91,7 @@ module('HLS', { | ... | @@ -91,6 +91,7 @@ module('HLS', { |
91 | oldSourceBuffer = window.videojs.SourceBuffer; | 91 | oldSourceBuffer = window.videojs.SourceBuffer; |
92 | window.videojs.SourceBuffer = function() { | 92 | window.videojs.SourceBuffer = function() { |
93 | this.appendBuffer = function() {}; | 93 | this.appendBuffer = function() {}; |
94 | this.abort = function() {}; | ||
94 | }; | 95 | }; |
95 | 96 | ||
96 | // force native HLS to be ignored | 97 | // force native HLS to be ignored |
... | @@ -765,6 +766,7 @@ test('drops tags before the target timestamp when seeking', function() { | ... | @@ -765,6 +766,7 @@ test('drops tags before the target timestamp when seeking', function() { |
765 | this.appendBuffer = function(chunk) { | 766 | this.appendBuffer = function(chunk) { |
766 | bytes.push(chunk); | 767 | bytes.push(chunk); |
767 | }; | 768 | }; |
769 | this.abort = function() {}; | ||
768 | }; | 770 | }; |
769 | // capture timeouts | 771 | // capture timeouts |
770 | window.setTimeout = function(callback) { | 772 | window.setTimeout = function(callback) { |
... | @@ -806,9 +808,11 @@ test('drops tags before the target timestamp when seeking', function() { | ... | @@ -806,9 +808,11 @@ test('drops tags before the target timestamp when seeking', function() { |
806 | }); | 808 | }); |
807 | 809 | ||
808 | test('clears pending buffer updates when seeking', function() { | 810 | test('clears pending buffer updates when seeking', function() { |
809 | var bytes = [], | 811 | var |
810 | callbacks = [], | 812 | bytes = [], |
811 | tags = [{ pts: 0, bytes: 0 }]; | 813 | callbacks = [], |
814 | aborts = 0, | ||
815 | tags = [{ pts: 0, bytes: 0 }]; | ||
812 | 816 | ||
813 | // mock out the parser and source buffer | 817 | // mock out the parser and source buffer |
814 | videojs.hls.SegmentParser = mockSegmentParser(tags); | 818 | videojs.hls.SegmentParser = mockSegmentParser(tags); |
... | @@ -816,6 +820,9 @@ test('clears pending buffer updates when seeking', function() { | ... | @@ -816,6 +820,9 @@ test('clears pending buffer updates when seeking', function() { |
816 | this.appendBuffer = function(chunk) { | 820 | this.appendBuffer = function(chunk) { |
817 | bytes.push(chunk); | 821 | bytes.push(chunk); |
818 | }; | 822 | }; |
823 | this.abort = function() { | ||
824 | aborts++; | ||
825 | }; | ||
819 | }; | 826 | }; |
820 | // capture timeouts | 827 | // capture timeouts |
821 | window.setTimeout = function(callback) { | 828 | window.setTimeout = function(callback) { |
... | @@ -843,7 +850,7 @@ test('clears pending buffer updates when seeking', function() { | ... | @@ -843,7 +850,7 @@ test('clears pending buffer updates when seeking', function() { |
843 | callbacks.shift()(); | 850 | callbacks.shift()(); |
844 | } | 851 | } |
845 | 852 | ||
846 | deepEqual(bytes, ['flv', 7], 'tags queued to be appended should be cancelled'); | 853 | strictEqual(1, aborts, 'aborted pending buffer'); |
847 | }); | 854 | }); |
848 | 855 | ||
849 | test('playlist 404 should trigger MEDIA_ERR_NETWORK', function() { | 856 | test('playlist 404 should trigger MEDIA_ERR_NETWORK', function() { |
... | @@ -1129,9 +1136,12 @@ test('only reloads the active media playlist', function() { | ... | @@ -1129,9 +1136,12 @@ test('only reloads the active media playlist', function() { |
1129 | videojs.mediaSources[player.currentSrc()].trigger({ | 1136 | videojs.mediaSources[player.currentSrc()].trigger({ |
1130 | type: 'sourceopen' | 1137 | type: 'sourceopen' |
1131 | }); | 1138 | }); |
1139 | |||
1132 | standardXHRResponse(requests[0]); | 1140 | standardXHRResponse(requests[0]); |
1133 | standardXHRResponse(requests[1]); | 1141 | standardXHRResponse(requests[1]); |
1134 | 1142 | ||
1143 | videojs.mediaSources[player.currentSrc()].endOfStream = function() {}; | ||
1144 | |||
1135 | player.hls.selectPlaylist = function() { | 1145 | player.hls.selectPlaylist = function() { |
1136 | return player.hls.master.playlists[1]; | 1146 | return player.hls.master.playlists[1]; |
1137 | }; | 1147 | }; | ... | ... |
-
Please register or sign in to post a comment