Calculate bandwidth when downloading segments
Track the XHR duration and use that to figure out bandwidth when downloading segments. Ensure a fresh instance is assigned to player.hls on each plugin invocation so that state attached to the plugin object is not retained across loads.
Showing
2 changed files
with
47 additions
and
4 deletions
... | @@ -10,7 +10,7 @@ | ... | @@ -10,7 +10,7 @@ |
10 | 10 | ||
11 | videojs.hls = {}; | 11 | videojs.hls = {}; |
12 | 12 | ||
13 | videojs.plugin('hls', function(options) { | 13 | var init = function(options) { |
14 | var | 14 | var |
15 | mediaSource = new videojs.MediaSource(), | 15 | mediaSource = new videojs.MediaSource(), |
16 | segmentParser = new videojs.hls.SegmentParser(), | 16 | segmentParser = new videojs.hls.SegmentParser(), |
... | @@ -53,7 +53,8 @@ videojs.plugin('hls', function(options) { | ... | @@ -53,7 +53,8 @@ videojs.plugin('hls', function(options) { |
53 | var | 53 | var |
54 | xhr = new window.XMLHttpRequest(), | 54 | xhr = new window.XMLHttpRequest(), |
55 | segment = player.hls.currentPlaylist.segments[player.hls.currentMediaIndex], | 55 | segment = player.hls.currentPlaylist.segments[player.hls.currentMediaIndex], |
56 | segmentUri = segment.uri; | 56 | segmentUri = segment.uri, |
57 | startTime; | ||
57 | if (!(/^([A-z]*:)?\/\//).test(segmentUri)) { | 58 | if (!(/^([A-z]*:)?\/\//).test(segmentUri)) { |
58 | // the segment URI is relative to the manifest | 59 | // the segment URI is relative to the manifest |
59 | segmentUri = url.split('/').slice(0, -1).concat(segmentUri).join('/'); | 60 | segmentUri = url.split('/').slice(0, -1).concat(segmentUri).join('/'); |
... | @@ -61,15 +62,24 @@ videojs.plugin('hls', function(options) { | ... | @@ -61,15 +62,24 @@ videojs.plugin('hls', function(options) { |
61 | xhr.open('GET', segmentUri); | 62 | xhr.open('GET', segmentUri); |
62 | xhr.responseType = 'arraybuffer'; | 63 | xhr.responseType = 'arraybuffer'; |
63 | xhr.onreadystatechange = function() { | 64 | xhr.onreadystatechange = function() { |
65 | var elapsed; | ||
64 | if (xhr.readyState === 4) { | 66 | if (xhr.readyState === 4) { |
65 | player.hls.currentMediaIndex++; | 67 | // calculate the download bandwidth |
68 | elapsed = ((+new Date()) - startTime) * 1000; | ||
69 | player.hls.bandwidth = xhr.response.byteLength / elapsed; | ||
70 | |||
71 | // transmux the segment data from M2TS to FLV | ||
66 | segmentParser.parseSegmentBinaryData(new Uint8Array(xhr.response)); | 72 | segmentParser.parseSegmentBinaryData(new Uint8Array(xhr.response)); |
67 | while (segmentParser.tagsAvailable()) { | 73 | while (segmentParser.tagsAvailable()) { |
68 | player.hls.sourceBuffer.appendBuffer(segmentParser.getNextTag().bytes, | 74 | player.hls.sourceBuffer.appendBuffer(segmentParser.getNextTag().bytes, |
69 | player); | 75 | player); |
70 | } | 76 | } |
77 | |||
78 | // update the segment index | ||
79 | player.hls.currentMediaIndex++; | ||
71 | } | 80 | } |
72 | }; | 81 | }; |
82 | startTime = +new Date(); | ||
73 | xhr.send(null); | 83 | xhr.send(null); |
74 | }; | 84 | }; |
75 | player.on('loadedmetadata', fillBuffer); | 85 | player.on('loadedmetadata', fillBuffer); |
... | @@ -102,6 +112,16 @@ videojs.plugin('hls', function(options) { | ... | @@ -102,6 +112,16 @@ videojs.plugin('hls', function(options) { |
102 | src: videojs.URL.createObjectURL(mediaSource), | 112 | src: videojs.URL.createObjectURL(mediaSource), |
103 | type: "video/flv" | 113 | type: "video/flv" |
104 | }); | 114 | }); |
115 | }; | ||
116 | |||
117 | videojs.plugin('hls', function() { | ||
118 | var initialize = function() { | ||
119 | return function() { | ||
120 | this.hls = initialize(); | ||
121 | init.apply(this, arguments); | ||
122 | }; | ||
123 | }; | ||
124 | initialize().apply(this, arguments); | ||
105 | }); | 125 | }); |
106 | 126 | ||
107 | })(window, window.videojs); | 127 | })(window, window.videojs); | ... | ... |
... | @@ -42,6 +42,7 @@ module('HLS', { | ... | @@ -42,6 +42,7 @@ module('HLS', { |
42 | manifestName = manifestName[1]; | 42 | manifestName = manifestName[1]; |
43 | } | 43 | } |
44 | this.responseText = window.manifests[manifestName || xhrParams[1]]; | 44 | this.responseText = window.manifests[manifestName || xhrParams[1]]; |
45 | this.response = new Uint8Array([1]).buffer; | ||
45 | 46 | ||
46 | this.readyState = 4; | 47 | this.readyState = 4; |
47 | this.onreadystatechange(); | 48 | this.onreadystatechange(); |
... | @@ -93,7 +94,7 @@ test('starts downloading a segment on loadedmetadata', function() { | ... | @@ -93,7 +94,7 @@ test('starts downloading a segment on loadedmetadata', function() { |
93 | strictEqual(xhrParams[1], 'manifest/00001.ts', 'the first segment is requested'); | 94 | strictEqual(xhrParams[1], 'manifest/00001.ts', 'the first segment is requested'); |
94 | }); | 95 | }); |
95 | 96 | ||
96 | test('recognizes absolute URIs and uses them umnodified', function() { | 97 | test('recognizes absolute URIs and requests them unmodified', function() { |
97 | player.hls('manifest/absoluteUris.m3u8'); | 98 | player.hls('manifest/absoluteUris.m3u8'); |
98 | videojs.mediaSources[player.currentSrc()].trigger({ | 99 | videojs.mediaSources[player.currentSrc()].trigger({ |
99 | type: 'sourceopen' | 100 | type: 'sourceopen' |
... | @@ -104,6 +105,28 @@ test('recognizes absolute URIs and uses them umnodified', function() { | ... | @@ -104,6 +105,28 @@ test('recognizes absolute URIs and uses them umnodified', function() { |
104 | 'the first segment is requested'); | 105 | 'the first segment is requested'); |
105 | }); | 106 | }); |
106 | 107 | ||
108 | test('re-initializes the plugin for each source', function() { | ||
109 | var firstInit, secondInit; | ||
110 | player.hls('manifest/master.m3u8'); | ||
111 | firstInit = player.hls; | ||
112 | player.hls('manifest/master.m3u8'); | ||
113 | secondInit = player.hls; | ||
114 | |||
115 | notStrictEqual(firstInit, secondInit, 'the plugin object is replaced'); | ||
116 | |||
117 | }); | ||
118 | |||
119 | test('calculates the bandwidth after downloading a segment', function() { | ||
120 | player.hls('manifest/media.m3u8'); | ||
121 | videojs.mediaSources[player.currentSrc()].trigger({ | ||
122 | type: 'sourceopen' | ||
123 | }); | ||
124 | |||
125 | ok(player.hls.bandwidth, 'bandwidth is calculated'); | ||
126 | ok(player.hls.bandwidth > 0, | ||
127 | 'bandwidth is positive: ' + player.hls.bandwidth); | ||
128 | }); | ||
129 | |||
107 | module('segment controller', { | 130 | module('segment controller', { |
108 | setup: function() { | 131 | setup: function() { |
109 | segmentController = new window.videojs.hls.SegmentController(); | 132 | segmentController = new window.videojs.hls.SegmentController(); | ... | ... |
-
Please register or sign in to post a comment