toms intro to jshint
Showing
6 changed files
with
397 additions
and
390 deletions
... | @@ -3,8 +3,8 @@ | ... | @@ -3,8 +3,8 @@ |
3 | ManifestController = window.videojs.hls.ManifestController, | 3 | ManifestController = window.videojs.hls.ManifestController, |
4 | SegmentController = window.videojs.hls.SegmentController, | 4 | SegmentController = window.videojs.hls.SegmentController, |
5 | MediaSource = window.videojs.MediaSource, | 5 | MediaSource = window.videojs.MediaSource, |
6 | SegmentParser = window.videojs.hls.SegmentParser, | 6 | SegmentParser = window.videojs.hls.SegmentParser; |
7 | M3U8 = window.videojs.hls.M3U8; | 7 | |
8 | 8 | ||
9 | window.videojs.hls.HLSPlaybackController = function(player) { | 9 | window.videojs.hls.HLSPlaybackController = function(player) { |
10 | 10 | ||
... | @@ -23,14 +23,14 @@ | ... | @@ -23,14 +23,14 @@ |
23 | self.loadManifest(self.currentRendition.url, self.onM3U8LoadComplete, self.onM3U8LoadError, self.onM3U8Update); | 23 | self.loadManifest(self.currentRendition.url, self.onM3U8LoadComplete, self.onM3U8LoadError, self.onM3U8Update); |
24 | }; | 24 | }; |
25 | 25 | ||
26 | self.loadManifest = function(manifestUrl, onDataCallback, onErrorCallback, onUpdateCallback) { | 26 | self.loadManifest = function(manifestUrl, onDataCallback) { |
27 | self.mediaSource.addEventListener('sourceopen', function(event) { | 27 | self.mediaSource.addEventListener('sourceopen', function() { |
28 | // feed parsed bytes into the player | 28 | // feed parsed bytes into the player |
29 | self.sourceBuffer = self.mediaSource.addSourceBuffer('video/flv; codecs="vp6,aac"'); | 29 | self.sourceBuffer = self.mediaSource.addSourceBuffer('video/flv; codecs="vp6,aac"'); |
30 | 30 | ||
31 | self.parser = new SegmentParser(); | 31 | self.parser = new SegmentParser(); |
32 | 32 | ||
33 | self.sourceBuffer.appendBuffer(self.parser.getFlvHeader(), video); | 33 | self.sourceBuffer.appendBuffer(self.parser.getFlvHeader(), self.player); |
34 | 34 | ||
35 | if (onDataCallback) { | 35 | if (onDataCallback) { |
36 | self.manifestLoadCompleteCallback = onDataCallback; | 36 | self.manifestLoadCompleteCallback = onDataCallback; |
... | @@ -42,7 +42,7 @@ | ... | @@ -42,7 +42,7 @@ |
42 | }, false); | 42 | }, false); |
43 | 43 | ||
44 | self.player.src({ | 44 | self.player.src({ |
45 | src: videojs.URL.createObjectURL(self.mediaSource), | 45 | src: window.videojs.URL.createObjectURL(self.mediaSource), |
46 | type: "video/flv" | 46 | type: "video/flv" |
47 | }); | 47 | }); |
48 | }; | 48 | }; |
... | @@ -65,8 +65,18 @@ | ... | @@ -65,8 +65,18 @@ |
65 | } | 65 | } |
66 | }; | 66 | }; |
67 | 67 | ||
68 | self.onM3U8LoadError = function(error) {}; | 68 | self.onM3U8LoadError = function(error) { |
69 | self.onM3U8Update = function(m3u8) {}; | 69 | if(error) |
70 | { | ||
71 | console.log(error); | ||
72 | } | ||
73 | }; | ||
74 | self.onM3U8Update = function(m3u8) { | ||
75 | if(m3u8) | ||
76 | { | ||
77 | console.log(m3u8); | ||
78 | } | ||
79 | }; | ||
70 | 80 | ||
71 | self.loadSegment = function(segment) { | 81 | self.loadSegment = function(segment) { |
72 | self.segmentController = new SegmentController(); | 82 | self.segmentController = new SegmentController(); |
... | @@ -88,9 +98,14 @@ | ... | @@ -88,9 +98,14 @@ |
88 | self.loadNextSegment = function() { | 98 | self.loadNextSegment = function() { |
89 | self.currentSegment++; | 99 | self.currentSegment++; |
90 | self.loadSegment(self.currentManifest.mediaItems[self.currentSegment]); | 100 | self.loadSegment(self.currentManifest.mediaItems[self.currentSegment]); |
91 | } | 101 | }; |
92 | 102 | ||
93 | self.onSegmentLoadError = function(error) {}; | 103 | self.onSegmentLoadError = function(error) { |
104 | if(error) | ||
105 | { | ||
106 | console.log(error); | ||
107 | } | ||
108 | }; | ||
94 | 109 | ||
95 | }; | 110 | }; |
96 | })(this); | 111 | })(this); | ... | ... |
... | @@ -38,11 +38,11 @@ | ... | @@ -38,11 +38,11 @@ |
38 | lines = rawDataString.split('\n'); | 38 | lines = rawDataString.split('\n'); |
39 | 39 | ||
40 | lines.forEach(function(value,index) { | 40 | lines.forEach(function(value,index) { |
41 | var segment, rendition, attribute; | 41 | var segment, rendition, attributes; |
42 | 42 | ||
43 | switch (self.getTagType(value)) { | 43 | switch (self.getTagType(value)) { |
44 | case tagTypes.EXTM3U: | 44 | case tagTypes.EXTM3U: |
45 | data.hasValidM3UTag = (index == 0); | 45 | data.hasValidM3UTag = (index === 0); |
46 | if (!data.hasValidM3UTag) { | 46 | if (!data.hasValidM3UTag) { |
47 | data.invalidReasons.push("Invalid EXTM3U Tag"); | 47 | data.invalidReasons.push("Invalid EXTM3U Tag"); |
48 | } | 48 | } |
... | @@ -95,12 +95,12 @@ | ... | @@ -95,12 +95,12 @@ |
95 | 95 | ||
96 | if (rendition[attrValue.split('=')[0].toLowerCase()].split('x').length === 2) { | 96 | if (rendition[attrValue.split('=')[0].toLowerCase()].split('x').length === 2) { |
97 | rendition.resolution = { | 97 | rendition.resolution = { |
98 | width: parseInt(rendition[attrValue.split('=')[0].toLowerCase()].split('x')[0]), | 98 | width: parseInt(rendition[attrValue.split('=')[0].toLowerCase()].split('x')[0],10), |
99 | height: parseInt(rendition[attrValue.split('=')[0].toLowerCase()].split('x')[1]) | 99 | height: parseInt(rendition[attrValue.split('=')[0].toLowerCase()].split('x')[1],10) |
100 | } | 100 | }; |
101 | } | 101 | } |
102 | } else { | 102 | } else { |
103 | rendition[attrValue.split('=')[0].toLowerCase()] = parseInt(attrValue.split('=')[1]); | 103 | rendition[attrValue.split('=')[0].toLowerCase()] = parseInt(attrValue.split('=')[1],10); |
104 | } | 104 | } |
105 | }); | 105 | }); |
106 | 106 | ||
... | @@ -128,7 +128,7 @@ | ... | @@ -128,7 +128,7 @@ |
128 | break; | 128 | break; |
129 | 129 | ||
130 | case tagTypes.MEDIA_SEQUENCE: | 130 | case tagTypes.MEDIA_SEQUENCE: |
131 | data.mediaSequence = parseInt(self.getTagValue(value)); | 131 | data.mediaSequence = parseInt(self.getTagValue(value),10); |
132 | break; | 132 | break; |
133 | 133 | ||
134 | case tagTypes.ALLOW_CACHE: | 134 | case tagTypes.ALLOW_CACHE: | ... | ... |
1 | (function (window) { | 1 | (function (window) { |
2 | var | 2 | var |
3 | M3U8 = window.videojs.hls.M3U8, | ||
4 | M3U8Parser = window.videojs.hls.M3U8Parser; | 3 | M3U8Parser = window.videojs.hls.M3U8Parser; |
5 | 4 | ||
6 | window.videojs.hls.ManifestController = function() { | 5 | window.videojs.hls.ManifestController = function() { |
7 | var self = this; | 6 | var self = this; |
8 | 7 | ||
9 | self.parser; | ||
10 | self.data; | ||
11 | self.url; | ||
12 | |||
13 | self.onDataCallback; | ||
14 | self.onErrorCallback; | ||
15 | self.onUpdateCallback; | ||
16 | |||
17 | self.loadManifest = function(manifestUrl, onDataCallback, onErrorCallback, onUpdateCallback) { | 8 | self.loadManifest = function(manifestUrl, onDataCallback, onErrorCallback, onUpdateCallback) { |
18 | self.url = manifestUrl; | 9 | self.url = manifestUrl; |
19 | 10 | ||
... | @@ -28,7 +19,7 @@ | ... | @@ -28,7 +19,7 @@ |
28 | self.onUpdateCallback = onUpdateCallback; | 19 | self.onUpdateCallback = onUpdateCallback; |
29 | } | 20 | } |
30 | 21 | ||
31 | vjs.get(manifestUrl, self.onManifestLoadComplete, self.onManifestLoadError); | 22 | window.vjs.get(manifestUrl, self.onManifestLoadComplete, self.onManifestLoadError); |
32 | }; | 23 | }; |
33 | 24 | ||
34 | self.parseManifest = function(dataAsString) { | 25 | self.parseManifest = function(dataAsString) { |
... | @@ -42,15 +33,15 @@ | ... | @@ -42,15 +33,15 @@ |
42 | self.onManifestLoadComplete = function(response) { | 33 | self.onManifestLoadComplete = function(response) { |
43 | var output = self.parseManifest(response); | 34 | var output = self.parseManifest(response); |
44 | 35 | ||
45 | if (self.onDataCallback != undefined) { | 36 | if (self.onDataCallback !== undefined) { |
46 | self.onDataCallback(output); | 37 | self.onDataCallback(output); |
47 | } | 38 | } |
48 | }; | 39 | }; |
49 | 40 | ||
50 | self.onManifestLoadError = function(err) { | 41 | self.onManifestLoadError = function(err) { |
51 | if (self.onErrorCallback != undefined) { | 42 | if (self.onErrorCallback !== undefined) { |
52 | self.onErrorCallback((err != undefined) ? err : null); | 43 | self.onErrorCallback((err !== undefined) ? err : null); |
53 | } | 44 | } |
54 | }; | 45 | }; |
55 | } | 46 | }; |
56 | })(this); | 47 | })(this); | ... | ... |
... | @@ -14,7 +14,7 @@ | ... | @@ -14,7 +14,7 @@ |
14 | 14 | ||
15 | request.open('GET', segmentUrl, true); | 15 | request.open('GET', segmentUrl, true); |
16 | request.responseType = 'arraybuffer'; | 16 | request.responseType = 'arraybuffer'; |
17 | request.onload = function(response) { | 17 | request.onload = function() { |
18 | self.onSegmentLoadComplete(new Uint8Array(request.response)); | 18 | self.onSegmentLoadComplete(new Uint8Array(request.response)); |
19 | }; | 19 | }; |
20 | 20 | ||
... | @@ -29,7 +29,7 @@ | ... | @@ -29,7 +29,7 @@ |
29 | self.data.requestTimestamp = self.requestTimestamp; | 29 | self.data.requestTimestamp = self.requestTimestamp; |
30 | self.data.responseTimestamp = self.responseTimestamp; | 30 | self.data.responseTimestamp = self.responseTimestamp; |
31 | self.data.byteLength = incomingData.byteLength; | 31 | self.data.byteLength = incomingData.byteLength; |
32 | self.data.isCached = parseInt(self.responseTimestamp - self.requestTimestamp) < 75; | 32 | self.data.isCached = parseInt(self.responseTimestamp - self.requestTimestamp,10) < 75; |
33 | self.data.throughput = self.calculateThroughput(self.data.byteLength, self.requestTimestamp ,self.responseTimestamp); | 33 | self.data.throughput = self.calculateThroughput(self.data.byteLength, self.requestTimestamp ,self.responseTimestamp); |
34 | 34 | ||
35 | return self.data; | 35 | return self.data; |
... | @@ -37,7 +37,7 @@ | ... | @@ -37,7 +37,7 @@ |
37 | 37 | ||
38 | self.calculateThroughput = function(dataAmount, startTime, endTime) { | 38 | self.calculateThroughput = function(dataAmount, startTime, endTime) { |
39 | return Math.round(dataAmount / (endTime - startTime) * 1000) * 8; | 39 | return Math.round(dataAmount / (endTime - startTime) * 1000) * 8; |
40 | } | 40 | }; |
41 | 41 | ||
42 | self.onSegmentLoadComplete = function(response) { | 42 | self.onSegmentLoadComplete = function(response) { |
43 | var output; | 43 | var output; |
... | @@ -57,8 +57,8 @@ | ... | @@ -57,8 +57,8 @@ |
57 | } | 57 | } |
58 | 58 | ||
59 | if (self.onErrorCallback !== undefined) { | 59 | if (self.onErrorCallback !== undefined) { |
60 | onErrorCallback(error); | 60 | self.onErrorCallback(error); |
61 | } | 61 | } |
62 | }; | 62 | }; |
63 | } | 63 | }; |
64 | })(this); | 64 | })(this); | ... | ... |
1 | (function (window) { | 1 | (function (window) { |
2 | /* | 2 | /* |
3 | ======== A Handy Little QUnit Reference ======== | 3 | ======== A Handy Little QUnit Reference ======== |
4 | http://api.qunitjs.com/ | 4 | http://api.qunitjs.com/ |
5 | 5 | ||
6 | Test methods: | 6 | Test methods: |
7 | module(name, {[setup][ ,teardown]}) | 7 | module(name, {[setup][ ,teardown]}) |
8 | test(name, callback) | 8 | test(name, callback) |
9 | expect(numberOfAssertions) | 9 | expect(numberOfAssertions) |
10 | stop(increment) | 10 | stop(increment) |
11 | start(decrement) | 11 | start(decrement) |
12 | Test assertions: | 12 | Test assertions: |
13 | ok(value, [message]) | 13 | ok(value, [message]) |
14 | equal(actual, expected, [message]) | 14 | equal(actual, expected, [message]) |
15 | notEqual(actual, expected, [message]) | 15 | notEqual(actual, expected, [message]) |
16 | deepEqual(actual, expected, [message]) | 16 | deepEqual(actual, expected, [message]) |
17 | notDeepEqual(actual, expected, [message]) | 17 | notDeepEqual(actual, expected, [message]) |
18 | strictEqual(actual, expected, [message]) | 18 | strictEqual(actual, expected, [message]) |
19 | notStrictEqual(actual, expected, [message]) | 19 | notStrictEqual(actual, expected, [message]) |
20 | throws(block, [expected], [message]) | 20 | throws(block, [expected], [message]) |
21 | */ | 21 | */ |
22 | var | 22 | var |
23 | manifestController, | 23 | manifestController, |
24 | segmentController, | 24 | segmentController, |
25 | m3u8parser, | 25 | m3u8parser, |
26 | parser, | 26 | parser, |
27 | 27 | ||
28 | expectedHeader = [ | 28 | expectedHeader = [ |
29 | 0x46, 0x4c, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, | 29 | 0x46, 0x4c, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, |
30 | 0x09, 0x00, 0x00, 0x00, 0x00 | 30 | 0x09, 0x00, 0x00, 0x00, 0x00 |
31 | ], | 31 | ], |
32 | testAudioTag, | 32 | testAudioTag, |
33 | testVideoTag, | 33 | testVideoTag, |
34 | testScriptTag, | 34 | testScriptTag, |
35 | asciiFromBytes, | 35 | asciiFromBytes, |
36 | testScriptString, | 36 | testScriptString, |
37 | testScriptEcmaArray; | 37 | testScriptEcmaArray; |
38 | 38 | ||
39 | module('environment'); | 39 | module('environment'); |
40 | 40 | ||
41 | test('is sane', function () { | 41 | test('is sane', function () { |
42 | expect(1); | 42 | expect(1); |
43 | ok(true); | 43 | ok(true); |
44 | }); | 44 | }); |
45 | 45 | ||
46 | module('segment parser', { | 46 | module('segment parser', { |
47 | setup: function () { | 47 | setup: function () { |
48 | parser = new window.videojs.hls.SegmentParser(); | 48 | parser = new window.videojs.hls.SegmentParser(); |
49 | } | 49 | } |
50 | }); | 50 | }); |
51 | 51 | ||
52 | test('creates an flv header', function () { | 52 | test('creates an flv header', function () { |
53 | var header = Array.prototype.slice.call(parser.getFlvHeader()); | 53 | var header = Array.prototype.slice.call(parser.getFlvHeader()); |
54 | ok(header, 'the header is truthy'); | 54 | ok(header, 'the header is truthy'); |
55 | equal(9 + 4, header.length, 'the header length is correct'); | 55 | equal(9 + 4, header.length, 'the header length is correct'); |
56 | equal(header[0], 'F'.charCodeAt(0), 'the first character is "F"'); | 56 | equal(header[0], 'F'.charCodeAt(0), 'the first character is "F"'); |
57 | equal(header[1], 'L'.charCodeAt(0), 'the second character is "L"'); | 57 | equal(header[1], 'L'.charCodeAt(0), 'the second character is "L"'); |
58 | equal(header[2], 'V'.charCodeAt(0), 'the third character is "V"'); | 58 | equal(header[2], 'V'.charCodeAt(0), 'the third character is "V"'); |
59 | 59 | ||
60 | deepEqual(expectedHeader, header, 'the rest of the header is correct'); | 60 | deepEqual(expectedHeader, header, 'the rest of the header is correct'); |
61 | }); | 61 | }); |
62 | 62 | ||
63 | test('parses the first bipbop segment', function () { | 63 | test('parses the first bipbop segment', function () { |
64 | var tag, bytes, i; | 64 | var tag, bytes, i; |
65 | parser.parseSegmentBinaryData(window.bcSegment); | 65 | parser.parseSegmentBinaryData(window.bcSegment); |
66 | 66 | ||
67 | ok(parser.tagsAvailable(), 'tags are available'); | 67 | ok(parser.tagsAvailable(), 'tags are available'); |
68 | 68 | ||
69 | console.log('h264 tags:', parser.stats.h264Tags(), | 69 | console.log('h264 tags:', parser.stats.h264Tags(), |
70 | 'aac tags:', parser.stats.aacTags()); | 70 | 'aac tags:', parser.stats.aacTags()); |
71 | }); | 71 | }); |
72 | 72 | ||
73 | testAudioTag = function (tag) { | 73 | testAudioTag = function (tag) { |
74 | var | 74 | var |
75 | byte = tag.bytes[11], | 75 | byte = tag.bytes[11], |
76 | format = (byte & 0xF0) >>> 4, | 76 | format = (byte & 0xF0) >>> 4, |
77 | soundRate = byte & 0x03, | 77 | soundRate = byte & 0x03, |
78 | soundSize = (byte & 0x2) >>> 1, | 78 | soundSize = (byte & 0x2) >>> 1, |
79 | soundType = byte & 0x1, | 79 | soundType = byte & 0x1, |
80 | aacPacketType = tag.bytes[12]; | 80 | aacPacketType = tag.bytes[12]; |
81 | 81 | ||
82 | equal(10, format, 'the audio format is aac'); | 82 | equal(10, format, 'the audio format is aac'); |
83 | equal(3, soundRate, 'the sound rate is 44kHhz'); | 83 | equal(3, soundRate, 'the sound rate is 44kHhz'); |
84 | equal(1, soundSize, 'the sound size is 16-bit samples'); | 84 | equal(1, soundSize, 'the sound size is 16-bit samples'); |
85 | equal(1, soundType, 'the sound type is stereo'); | 85 | equal(1, soundType, 'the sound type is stereo'); |
86 | 86 | ||
87 | ok(aacPacketType === 0 || aacPacketType === 1, 'aac packets should have a valid type'); | 87 | ok(aacPacketType === 0 || aacPacketType === 1, 'aac packets should have a valid type'); |
88 | }; | 88 | }; |
89 | 89 | ||
90 | testVideoTag = function (tag) { | 90 | testVideoTag = function (tag) { |
91 | var | 91 | var |
92 | byte = tag.bytes[11], | 92 | byte = tag.bytes[11], |
93 | frameType = (byte & 0xF0) >>> 4, | 93 | frameType = (byte & 0xF0) >>> 4, |
94 | codecId = byte & 0x0F, | 94 | codecId = byte & 0x0F, |
95 | packetType = tag.bytes[12], | 95 | packetType = tag.bytes[12], |
96 | compositionTime = (tag.view.getInt32(13) & 0xFFFFFF00) >> 8, | 96 | compositionTime = (tag.view.getInt32(13) & 0xFFFFFF00) >> 8, |
97 | nalHeader; | 97 | nalHeader; |
98 | 98 | ||
99 | // payload starts at tag.bytes[16] | 99 | // payload starts at tag.bytes[16] |
100 | 100 | ||
101 | 101 | ||
102 | // XXX: I'm not sure that frame types 3-5 are invalid | 102 | // XXX: I'm not sure that frame types 3-5 are invalid |
103 | ok(frameType === 1 || frameType === 2, | 103 | ok(frameType === 1 || frameType === 2, |
104 | 'the frame type should be valid'); | 104 | 'the frame type should be valid'); |
105 | 105 | ||
106 | equal(7, codecId, 'the codec ID is AVC for h264'); | 106 | equal(7, codecId, 'the codec ID is AVC for h264'); |
107 | ok(packetType <= 2 && packetType >= 0, 'the packet type is within [0, 2]'); | 107 | ok(packetType <= 2 && packetType >= 0, 'the packet type is within [0, 2]'); |
108 | if (packetType !== 1) { | 108 | if (packetType !== 1) { |
109 | equal(0, | 109 | equal(0, |
110 | compositionTime, | 110 | compositionTime, |
111 | 'the composition time is zero for non-NALU packets'); | 111 | 'the composition time is zero for non-NALU packets'); |
112 | } | 112 | } |
113 | 113 | ||
114 | // TODO: the rest of the bytes are an NLU unit | 114 | // TODO: the rest of the bytes are an NLU unit |
115 | if (packetType === 0) { | 115 | if (packetType === 0) { |
116 | // AVC decoder configuration record | 116 | // AVC decoder configuration record |
117 | } else { | 117 | } else { |
118 | // NAL units | 118 | // NAL units |
119 | testNalUnit(tag.bytes.subarray(16)); | 119 | testNalUnit(tag.bytes.subarray(16)); |
120 | } | 120 | } |
121 | }; | 121 | }; |
122 | 122 | ||
123 | testNalUnit = function (bytes) { | 123 | testNalUnit = function (bytes) { |
124 | var | 124 | var |
125 | nalHeader = bytes[0], | 125 | nalHeader = bytes[0], |
126 | unitType = nalHeader & 0x1F; | 126 | unitType = nalHeader & 0x1F; |
127 | 127 | ||
128 | equal(0, (nalHeader & 0x80) >>> 7, 'the first bit is always 0'); | 128 | equal(0, (nalHeader & 0x80) >>> 7, 'the first bit is always 0'); |
129 | // equal(90, (nalHeader & 0x60) >>> 5, 'the NAL reference indicator is something'); | 129 | // equal(90, (nalHeader & 0x60) >>> 5, 'the NAL reference indicator is something'); |
130 | // ok(unitType > 0, 'NAL unit type ' + unitType + ' is greater than 0'); | 130 | // ok(unitType > 0, 'NAL unit type ' + unitType + ' is greater than 0'); |
131 | // ok(unitType < 22 , 'NAL unit type ' + unitType + ' is less than 22'); | 131 | // ok(unitType < 22 , 'NAL unit type ' + unitType + ' is less than 22'); |
132 | }; | 132 | }; |
133 | 133 | ||
134 | 134 | ||
135 | asciiFromBytes = function (bytes) { | 135 | asciiFromBytes = function (bytes) { |
136 | var | 136 | var |
137 | string = [], | 137 | string = [], |
138 | i = bytes.byteLength; | 138 | i = bytes.byteLength; |
139 | 139 | ||
140 | while (i--) { | 140 | while (i--) { |
141 | string[i] = String.fromCharCode(bytes[i]); | 141 | string[i] = String.fromCharCode(bytes[i]); |
142 | } | 142 | } |
143 | return string.join(''); | 143 | return string.join(''); |
144 | }; | 144 | }; |
145 | 145 | ||
146 | testScriptString = function (tag, offset, expected) { | 146 | testScriptString = function (tag, offset, expected) { |
147 | var | 147 | var |
148 | type = tag.bytes[offset], | 148 | type = tag.bytes[offset], |
149 | stringLength = tag.view.getUint16(offset + 1), | 149 | stringLength = tag.view.getUint16(offset + 1), |
150 | string, | 150 | string, |
151 | i = expected.length; | 151 | i = expected.length; |
152 | 152 | ||
153 | equal(2, type, 'the script element is of string type'); | 153 | equal(2, type, 'the script element is of string type'); |
154 | equal(stringLength, expected.length, 'the script string length is correct'); | 154 | equal(stringLength, expected.length, 'the script string length is correct'); |
155 | string = asciiFromBytes(tag.bytes.subarray(offset + 3, | 155 | string = asciiFromBytes(tag.bytes.subarray(offset + 3, |
156 | offset + 3 + stringLength)); | 156 | offset + 3 + stringLength)); |
157 | equal(expected, string, 'the string value is "' + expected + '"'); | 157 | equal(expected, string, 'the string value is "' + expected + '"'); |
158 | }; | 158 | }; |
159 | 159 | ||
160 | testScriptEcmaArray = function (tag, start) { | 160 | testScriptEcmaArray = function (tag, start) { |
161 | var | 161 | var |
162 | numItems = tag.view.getUint32(start), | 162 | numItems = tag.view.getUint32(start), |
163 | i = numItems, | 163 | i = numItems, |
164 | offset = start + 4, | 164 | offset = start + 4, |
165 | length, | 165 | length, |
166 | type; | 166 | type; |
167 | 167 | ||
168 | while (i--) { | 168 | while (i--) { |
169 | length = tag.view.getUint16(offset); | 169 | length = tag.view.getUint16(offset); |
170 | 170 | ||
171 | // advance offset to the property value | 171 | // advance offset to the property value |
172 | offset += 2 + length; | 172 | offset += 2 + length; |
173 | 173 | ||
174 | type = tag.bytes[offset]; | 174 | type = tag.bytes[offset]; |
175 | ok(type === 1 || type === 0, | 175 | ok(type === 1 || type === 0, |
176 | 'the ecma array property value type is number or boolean'); | 176 | 'the ecma array property value type is number or boolean'); |
177 | offset++; | 177 | offset++; |
178 | if (type) { | 178 | if (type) { |
179 | // boolean | 179 | // boolean |
180 | ok(tag.bytes[offset] === 0 || tag.bytes[offset] === 1, | 180 | ok(tag.bytes[offset] === 0 || tag.bytes[offset] === 1, |
181 | 'the script boolean value is 0 or 1'); | 181 | 'the script boolean value is 0 or 1'); |
182 | offset++; | 182 | offset++; |
183 | } else { | 183 | } else { |
184 | // number | 184 | // number |
185 | ok(!isNaN(tag.view.getFloat64(offset)), 'the value is not NaN'); | 185 | ok(!isNaN(tag.view.getFloat64(offset)), 'the value is not NaN'); |
186 | offset += 8; | 186 | offset += 8; |
187 | } | 187 | } |
188 | } | 188 | } |
189 | equal(tag.bytes[offset], 0, 'the property array terminator is valid'); | 189 | equal(tag.bytes[offset], 0, 'the property array terminator is valid'); |
190 | equal(tag.bytes[offset + 1], 0, 'the property array terminator is valid'); | 190 | equal(tag.bytes[offset + 1], 0, 'the property array terminator is valid'); |
191 | equal(tag.bytes[offset + 2], 9, 'the property array terminator is valid'); | 191 | equal(tag.bytes[offset + 2], 9, 'the property array terminator is valid'); |
192 | }; | 192 | }; |
193 | 193 | ||
194 | testScriptTag = function (tag) { | 194 | testScriptTag = function (tag) { |
195 | testScriptString(tag, 11, 'onMetaData'); | 195 | testScriptString(tag, 11, 'onMetaData'); |
196 | 196 | ||
197 | // the onMetaData object is stored as an 'ecma array', an array with non- | 197 | // the onMetaData object is stored as an 'ecma array', an array with non- |
198 | // integer indices (i.e. a dictionary or hash-map). | 198 | // integer indices (i.e. a dictionary or hash-map). |
199 | equal(8, tag.bytes[24], 'onMetaData is of ecma array type'); | 199 | equal(8, tag.bytes[24], 'onMetaData is of ecma array type'); |
200 | testScriptEcmaArray(tag, 25); | 200 | testScriptEcmaArray(tag, 25); |
201 | }; | 201 | }; |
202 | 202 | ||
203 | test('the flv tags are well-formed', function () { | 203 | test('the flv tags are well-formed', function () { |
204 | var | 204 | var |
205 | tag, | 205 | tag, |
206 | byte, | 206 | byte, |
207 | type, | 207 | type, |
208 | lastTime = 0; | 208 | lastTime = 0; |
209 | parser.parseSegmentBinaryData(window.bcSegment); | 209 | parser.parseSegmentBinaryData(window.bcSegment); |
210 | 210 | ||
211 | while (parser.tagsAvailable()) { | 211 | while (parser.tagsAvailable()) { |
212 | tag = parser.getNextTag(); | 212 | tag = parser.getNextTag(); |
213 | type = tag.bytes[0]; | 213 | type = tag.bytes[0]; |
214 | 214 | ||
215 | // generic flv headers | 215 | // generic flv headers |
216 | ok(type === 8 || type === 9 || type === 18, | 216 | ok(type === 8 || type === 9 || type === 18, |
217 | 'the type field specifies audio, video or script'); | 217 | 'the type field specifies audio, video or script'); |
218 | 218 | ||
219 | byte = (tag.view.getUint32(1) & 0xFFFFFF00) >>> 8; | 219 | byte = (tag.view.getUint32(1) & 0xFFFFFF00) >>> 8; |
220 | equal(tag.bytes.byteLength - 11 - 4, byte, 'the size field is correct'); | 220 | equal(tag.bytes.byteLength - 11 - 4, byte, 'the size field is correct'); |
221 | 221 | ||
222 | byte = tag.view.getUint32(5) & 0xFFFFFF00; | 222 | byte = tag.view.getUint32(5) & 0xFFFFFF00; |
223 | ok(byte >= lastTime, 'the timestamp for the tag is greater than zero'); | 223 | ok(byte >= lastTime, 'the timestamp for the tag is greater than zero'); |
224 | lastTime = byte; | 224 | lastTime = byte; |
225 | 225 | ||
226 | // tag type-specific headers | 226 | // tag type-specific headers |
227 | ({ | 227 | ({ |
228 | 8: testAudioTag, | 228 | 8: testAudioTag, |
229 | 9: testVideoTag, | 229 | 9: testVideoTag, |
230 | 18: testScriptTag | 230 | 18: testScriptTag |
231 | })[type](tag); | 231 | })[type](tag); |
232 | 232 | ||
233 | // previous tag size | 233 | // previous tag size |
234 | equal(tag.bytes.byteLength - 4, | 234 | equal(tag.bytes.byteLength - 4, |
235 | tag.view.getUint32(tag.bytes.byteLength - 4), | 235 | tag.view.getUint32(tag.bytes.byteLength - 4), |
236 | 'the size of the previous tag is correct'); | 236 | 'the size of the previous tag is correct'); |
237 | } | 237 | } |
238 | }); | 238 | }); |
239 | 239 | ||
240 | /* | 240 | /* |
241 | M3U8 Test Suite | 241 | M3U8 Test Suite |
242 | */ | 242 | */ |
243 | 243 | ||
244 | module('m3u8 parser', { | 244 | module('m3u8 parser', { |
245 | setup: function () { | 245 | setup: function () { |
246 | m3u8parser = new window.videojs.hls.M3U8Parser(); | 246 | m3u8parser = new window.videojs.hls.M3U8Parser(); |
247 | } | 247 | } |
248 | }); | 248 | }); |
249 | 249 | ||
250 | test('should create my parser', function () { | 250 | test('should create my parser', function () { |
251 | ok(m3u8parser != undefined); | 251 | ok(m3u8parser != undefined); |
252 | }); | 252 | }); |
253 | 253 | ||
254 | test('should successfully parse manifest data', function () { | 254 | test('should successfully parse manifest data', function () { |
255 | var parsedData = m3u8parser.parse(window.playlistData); | 255 | var parsedData = m3u8parser.parse(window.playlistData); |
256 | ok(parsedData); | 256 | ok(parsedData); |
257 | }); | 257 | }); |
258 | 258 | ||
259 | test('test for expected results', function () { | 259 | test('test for expected results', function () { |
260 | var data = m3u8parser.parse(window.playlistData); | 260 | var data = m3u8parser.parse(window.playlistData); |
261 | 261 | ||
262 | notEqual(data, null, 'data is not NULL'); | 262 | notEqual(data, null, 'data is not NULL'); |
263 | equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); | 263 | equal(data.invalidReasons.length, 0, 'data has 0 invalid reasons'); |
264 | equal(data.hasValidM3UTag, true, 'data has valid EXTM3U'); | 264 | equal(data.hasValidM3UTag, true, 'data has valid EXTM3U'); |
265 | equal(data.targetDuration, 10, 'data has correct TARGET DURATION'); | 265 | equal(data.targetDuration, 10, 'data has correct TARGET DURATION'); |
266 | equal(data.allowCache, "NO", 'acceptable ALLOW CACHE'); | 266 | equal(data.allowCache, "NO", 'acceptable ALLOW CACHE'); |
267 | equal(data.isPlaylist, true, 'data is parsed as a PLAYLIST as expected'); | 267 | equal(data.isPlaylist, true, 'data is parsed as a PLAYLIST as expected'); |
268 | equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE'); | 268 | equal(data.playlistType, "VOD", 'acceptable PLAYLIST TYPE'); |
269 | equal(data.mediaItems.length, 16, 'acceptable mediaItem count'); | 269 | equal(data.mediaItems.length, 16, 'acceptable mediaItem count'); |
270 | equal(data.mediaSequence, 0, 'MEDIA SEQUENCE is correct'); | 270 | equal(data.mediaSequence, 0, 'MEDIA SEQUENCE is correct'); |
271 | equal(data.totalDuration, -1, "ZEN TOTAL DURATION is unknown as expected"); | 271 | equal(data.totalDuration, -1, "ZEN TOTAL DURATION is unknown as expected"); |
272 | equal(data.hasEndTag, true, 'should have ENDLIST tag'); | 272 | equal(data.hasEndTag, true, 'should have ENDLIST tag'); |
273 | }); | 273 | }); |
274 | 274 | ||
275 | module('brightcove playlist', { | 275 | module('brightcove playlist', { |
276 | setup: function () { | 276 | setup: function () { |
277 | m3u8parser = new window.videojs.hls.M3U8Parser(); | 277 | m3u8parser = new window.videojs.hls.M3U8Parser(); |
278 | } | 278 | } |
279 | }); | 279 | }); |
280 | 280 | ||
281 | test('should parse a brightcove manifest data', function () { | 281 | test('should parse a brightcove manifest data', function () { |
282 | var data = m3u8parser.parse(window.brightcove_playlist_data); | 282 | var data = m3u8parser.parse(window.brightcove_playlist_data); |
283 | 283 | ||
284 | ok(data); | 284 | ok(data); |
285 | equal(data.playlistItems.length, 4, 'Has correct rendition count'); | 285 | equal(data.playlistItems.length, 4, 'Has correct rendition count'); |
286 | equal(data.playlistItems[0].bandwidth, 240000, 'First rendition index bandwidth is correct'); | 286 | equal(data.playlistItems[0].bandwidth, 240000, 'First rendition index bandwidth is correct'); |
287 | equal(data.playlistItems[0]["program-id"], 1, 'First rendition index program-id is correct'); | 287 | equal(data.playlistItems[0]["program-id"], 1, 'First rendition index program-id is correct'); |
288 | equal(data.playlistItems[0].resolution.width, 396, 'First rendition index resolution width is correct'); | 288 | equal(data.playlistItems[0].resolution.width, 396, 'First rendition index resolution width is correct'); |
289 | equal(data.playlistItems[0].resolution.height, 224, 'First rendition index resolution height is correct'); | 289 | equal(data.playlistItems[0].resolution.height, 224, 'First rendition index resolution height is correct'); |
290 | 290 | ||
291 | } | 291 | } |
292 | ); | 292 | ); |
293 | 293 | ||
294 | module('manifest controller', { | 294 | module('manifest controller', { |
295 | setup: function () { | 295 | setup: function () { |
296 | manifestController = new window.videojs.hls.ManifestController(); | 296 | manifestController = new window.videojs.hls.ManifestController(); |
297 | this.vjsget = vjs.get; | 297 | this.vjsget = vjs.get; |
298 | vjs.get = function (url, success, error) { | 298 | vjs.get = function (url, success, error) { |
299 | success(window.brightcove_playlist_data); | 299 | success(window.brightcove_playlist_data); |
300 | }; | 300 | }; |
301 | }, | 301 | }, |
302 | teardown: function () { | 302 | teardown: function () { |
303 | vjs.get = this.vjsget; | 303 | vjs.get = this.vjsget; |
304 | } | 304 | } |
305 | }); | 305 | }); |
306 | 306 | ||
307 | test('should create', function () { | 307 | test('should create', function () { |
308 | ok(manifestController); | 308 | ok(manifestController); |
309 | }); | 309 | }); |
310 | 310 | ||
311 | test('should return a parsed object', function () { | 311 | test('should return a parsed object', function () { |
312 | var data = manifestController.parseManifest(window.brightcove_playlist_data); | 312 | var data = manifestController.parseManifest(window.brightcove_playlist_data); |
313 | 313 | ||
314 | ok(data); | 314 | ok(data); |
315 | equal(data.playlistItems.length, 4, 'Has correct rendition count'); | 315 | equal(data.playlistItems.length, 4, 'Has correct rendition count'); |
316 | equal(data.playlistItems[0].bandwidth, 240000, 'First rendition index bandwidth is correct'); | 316 | equal(data.playlistItems[0].bandwidth, 240000, 'First rendition index bandwidth is correct'); |
317 | equal(data.playlistItems[0]["program-id"], 1, 'First rendition index program-id is correct'); | 317 | equal(data.playlistItems[0]["program-id"], 1, 'First rendition index program-id is correct'); |
318 | equal(data.playlistItems[0].resolution.width, 396, 'First rendition index resolution width is correct'); | 318 | equal(data.playlistItems[0].resolution.width, 396, 'First rendition index resolution width is correct'); |
319 | equal(data.playlistItems[0].resolution.height, 224, 'First rendition index resolution height is correct'); | 319 | equal(data.playlistItems[0].resolution.height, 224, 'First rendition index resolution height is correct'); |
320 | }); | 320 | }); |
321 | 321 | ||
322 | test('should get a manifest from hermes', function () { | 322 | test('should get a manifest from hermes', function () { |
323 | manifestController.loadManifest('http://example.com/16x9-master.m3u8', | 323 | manifestController.loadManifest('http://example.com/16x9-master.m3u8', |
324 | function(responseData) { | 324 | function (responseData) { |
325 | ok(responseData); | 325 | ok(responseData); |
326 | }, | 326 | }, |
327 | function(errorData) { | 327 | function (errorData) { |
328 | ok(false, 'does not error'); | 328 | ok(false, 'does not error'); |
329 | }, | 329 | }, |
330 | function(updateData) {}); | 330 | function (updateData) { |
331 | }); | 331 | }); |
332 | 332 | }); | |
333 | module('segment controller', { | 333 | |
334 | setup: function () { | 334 | module('segment controller', { |
335 | segmentController = new window.videojs.hls.SegmentController(); | 335 | setup: function () { |
336 | this.vjsget = vjs.get; | 336 | segmentController = new window.videojs.hls.SegmentController(); |
337 | vjs.get = function (url, success, error) { | 337 | this.vjsget = vjs.get; |
338 | console.log('load segment url', url); | 338 | vjs.get = function (url, success, error) { |
339 | success(window.bcSegment); | 339 | console.log('load segment url', url); |
340 | }; | 340 | success(window.bcSegment); |
341 | }, | 341 | }; |
342 | teardown: function () { | 342 | }, |
343 | vjs.get = this.vjsget; | 343 | teardown: function () { |
344 | } | 344 | vjs.get = this.vjsget; |
345 | }); | 345 | } |
346 | 346 | }); | |
347 | test('bandwidth calulation test', function () { | 347 | |
348 | var | 348 | test('bandwidth calulation test', function () { |
349 | multiSecondData = segmentController.calculateThroughput(10000, 1000, 2000), | 349 | var |
350 | subSecondData = segmentController.calculateThroughput(10000, 1000, 1500); | 350 | multiSecondData = segmentController.calculateThroughput(10000, 1000, 2000), |
351 | equal(multiSecondData, 80000, 'MULTI-Second bits per second calculation'); | 351 | subSecondData = segmentController.calculateThroughput(10000, 1000, 1500); |
352 | equal(subSecondData, 160000, 'SUB-Second bits per second calculation'); | 352 | equal(multiSecondData, 80000, 'MULTI-Second bits per second calculation'); |
353 | }); | 353 | equal(subSecondData, 160000, 'SUB-Second bits per second calculation'); |
354 | }); | ||
354 | })(this); | 355 | })(this); | ... | ... |
-
Please register or sign in to post a comment