5587efc9 by Gary Katsevman

Merge branch 'master' into withcredentials

Conflicts:
	test/videojs-hls_test.js
2 parents 5be1a83d 45ec53ae
...@@ -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 [![Build Status](https://travis-ci.org/videojs/videojs-contrib-hls.svg?branch=master)](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 [![Build Status](https://travis-ci.org/videojs/videojs-contrib-hls.svg?branch=master)](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 }
......
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();
......
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",
......
...@@ -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,8 +808,10 @@ test('drops tags before the target timestamp when seeking', function() { ...@@ -806,8 +808,10 @@ 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
812 bytes = [],
810 callbacks = [], 813 callbacks = [],
814 aborts = 0,
811 tags = [{ pts: 0, bytes: 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
...@@ -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 };
......