Merge pull request #544 from BrandonOCasey/browserify-p4
browserify-p4: playlist*, xhr, and resolve-url
Showing
12 changed files
with
178 additions
and
137 deletions
... | @@ -48,10 +48,7 @@ | ... | @@ -48,10 +48,7 @@ |
48 | <script src="/node_modules/video.js/dist/video.js"></script> | 48 | <script src="/node_modules/video.js/dist/video.js"></script> |
49 | <script src="/node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script> | 49 | <script src="/node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script> |
50 | <script src="/src/videojs-contrib-hls.js"></script> | 50 | <script src="/src/videojs-contrib-hls.js"></script> |
51 | <script src="/src/xhr.js"></script> | ||
52 | <script src="/dist/videojs-contrib-hls.js"></script> | 51 | <script src="/dist/videojs-contrib-hls.js"></script> |
53 | <script src="/src/playlist.js"></script> | ||
54 | <script src="/src/playlist-loader.js"></script> | ||
55 | <script src="/src/bin-utils.js"></script> | 52 | <script src="/src/bin-utils.js"></script> |
56 | <script> | 53 | <script> |
57 | (function(window, videojs) { | 54 | (function(window, videojs) { | ... | ... |
... | @@ -2,7 +2,7 @@ var browserify = require('browserify'); | ... | @@ -2,7 +2,7 @@ var browserify = require('browserify'); |
2 | var fs = require('fs'); | 2 | var fs = require('fs'); |
3 | var glob = require('glob'); | 3 | var glob = require('glob'); |
4 | 4 | ||
5 | glob('test/{decryper,m3u8,stub}.test.js', function(err, files) { | 5 | glob('test/{playlist*,decryper,m3u8,stub}.test.js', function(err, files) { |
6 | browserify(files) | 6 | browserify(files) |
7 | .transform('babelify') | 7 | .transform('babelify') |
8 | .bundle() | 8 | .bundle() | ... | ... |
... | @@ -3,7 +3,7 @@ var fs = require('fs'); | ... | @@ -3,7 +3,7 @@ var fs = require('fs'); |
3 | var glob = require('glob'); | 3 | var glob = require('glob'); |
4 | var watchify = require('watchify'); | 4 | var watchify = require('watchify'); |
5 | 5 | ||
6 | glob('test/{decrypter,m3u8,stub}.test.js', function(err, files) { | 6 | glob('test/{playlist*,decrypter,m3u8,stub}.test.js', function(err, files) { |
7 | var b = browserify(files, { | 7 | var b = browserify(files, { |
8 | cache: {}, | 8 | cache: {}, |
9 | packageCache: {}, | 9 | packageCache: {}, | ... | ... |
... | @@ -5,14 +5,13 @@ | ... | @@ -5,14 +5,13 @@ |
5 | * M3U8 playlists. | 5 | * M3U8 playlists. |
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | (function(window, videojs) { | 8 | import resolveUrl from './resolve-url'; |
9 | 'use strict'; | 9 | import XhrModule from './xhr'; |
10 | var | 10 | import {mergeOptions} from 'video.js'; |
11 | resolveUrl = videojs.Hls.resolveUrl, | 11 | import Stream from './stream'; |
12 | xhr = videojs.Hls.xhr, | 12 | import m3u8 from './m3u8'; |
13 | mergeOptions = videojs.mergeOptions, | ||
14 | 13 | ||
15 | /** | 14 | /** |
16 | * Returns a new master playlist that is the result of merging an | 15 | * Returns a new master playlist that is the result of merging an |
17 | * updated media playlist into the original version. If the | 16 | * updated media playlist into the original version. If the |
18 | * updated media playlist does not match any of the playlist | 17 | * updated media playlist does not match any of the playlist |
... | @@ -23,14 +22,12 @@ | ... | @@ -23,14 +22,12 @@ |
23 | * master playlist with the updated media playlist merged in, or | 22 | * master playlist with the updated media playlist merged in, or |
24 | * null if the merge produced no change. | 23 | * null if the merge produced no change. |
25 | */ | 24 | */ |
26 | updateMaster = function(master, media) { | 25 | const updateMaster = function(master, media) { |
27 | var | 26 | let changed = false; |
28 | changed = false, | 27 | let result = mergeOptions(master, {}); |
29 | result = mergeOptions(master, {}), | 28 | let i = master.playlists.length; |
30 | i, | 29 | let playlist; |
31 | playlist; | 30 | |
32 | |||
33 | i = master.playlists.length; | ||
34 | while (i--) { | 31 | while (i--) { |
35 | playlist = result.playlists[i]; | 32 | playlist = result.playlists[i]; |
36 | if (playlist.uri === media.uri) { | 33 | if (playlist.uri === media.uri) { |
... | @@ -51,15 +48,16 @@ | ... | @@ -51,15 +48,16 @@ |
51 | if (playlist.segments) { | 48 | if (playlist.segments) { |
52 | result.playlists[i].segments = updateSegments(playlist.segments, | 49 | result.playlists[i].segments = updateSegments(playlist.segments, |
53 | media.segments, | 50 | media.segments, |
54 | media.mediaSequence - playlist.mediaSequence); | 51 | media.mediaSequence - |
52 | playlist.mediaSequence); | ||
55 | } | 53 | } |
56 | changed = true; | 54 | changed = true; |
57 | } | 55 | } |
58 | } | 56 | } |
59 | return changed ? result : null; | 57 | return changed ? result : null; |
60 | }, | 58 | }; |
61 | 59 | ||
62 | /** | 60 | /** |
63 | * Returns a new array of segments that is the result of merging | 61 | * Returns a new array of segments that is the result of merging |
64 | * properties from an older list of segments onto an updated | 62 | * properties from an older list of segments onto an updated |
65 | * list. No properties on the updated playlist will be overridden. | 63 | * list. No properties on the updated playlist will be overridden. |
... | @@ -73,8 +71,11 @@ | ... | @@ -73,8 +71,11 @@ |
73 | * playlists. | 71 | * playlists. |
74 | * @return a list of merged segment objects | 72 | * @return a list of merged segment objects |
75 | */ | 73 | */ |
76 | updateSegments = function(original, update, offset) { | 74 | const updateSegments = function(original, update, offset) { |
77 | var result = update.slice(), length, i; | 75 | let result = update.slice(); |
76 | let length; | ||
77 | let i; | ||
78 | |||
78 | offset = offset || 0; | 79 | offset = offset || 0; |
79 | length = Math.min(original.length, update.length + offset); | 80 | length = Math.min(original.length, update.length + offset); |
80 | 81 | ||
... | @@ -82,18 +83,17 @@ | ... | @@ -82,18 +83,17 @@ |
82 | result[i - offset] = mergeOptions(original[i], result[i - offset]); | 83 | result[i - offset] = mergeOptions(original[i], result[i - offset]); |
83 | } | 84 | } |
84 | return result; | 85 | return result; |
85 | }, | 86 | }; |
86 | 87 | ||
87 | PlaylistLoader = function(srcUrl, withCredentials) { | 88 | export default class PlaylistLoader extends Stream { |
88 | var | 89 | constructor(srcUrl, withCredentials) { |
89 | loader = this, | 90 | super(); |
90 | dispose, | 91 | let loader = this; |
91 | mediaUpdateTimeout, | 92 | let dispose; |
92 | request, | 93 | let mediaUpdateTimeout; |
93 | playlistRequestError, | 94 | let request; |
94 | haveMetadata; | 95 | let playlistRequestError; |
95 | 96 | let haveMetadata; | |
96 | PlaylistLoader.prototype.init.call(this); | ||
97 | 97 | ||
98 | // a flag that disables "expired time"-tracking this setting has | 98 | // a flag that disables "expired time"-tracking this setting has |
99 | // no effect when not playing a live stream | 99 | // no effect when not playing a live stream |
... | @@ -127,7 +127,9 @@ | ... | @@ -127,7 +127,9 @@ |
127 | // updated playlist. | 127 | // updated playlist. |
128 | 128 | ||
129 | haveMetadata = function(xhr, url) { | 129 | haveMetadata = function(xhr, url) { |
130 | var parser, refreshDelay, update; | 130 | let parser; |
131 | let refreshDelay; | ||
132 | let update; | ||
131 | 133 | ||
132 | loader.setBandwidth(request || xhr); | 134 | loader.setBandwidth(request || xhr); |
133 | 135 | ||
... | @@ -135,7 +137,7 @@ | ... | @@ -135,7 +137,7 @@ |
135 | request = null; | 137 | request = null; |
136 | loader.state = 'HAVE_METADATA'; | 138 | loader.state = 'HAVE_METADATA'; |
137 | 139 | ||
138 | parser = new videojs.m3u8.Parser(); | 140 | parser = new m3u8.Parser(); |
139 | parser.push(xhr.responseText); | 141 | parser.push(xhr.responseText); |
140 | parser.end(); | 142 | parser.end(); |
141 | parser.manifest.uri = url; | 143 | parser.manifest.uri = url; |
... | @@ -198,7 +200,8 @@ | ... | @@ -198,7 +200,8 @@ |
198 | * object to switch to | 200 | * object to switch to |
199 | */ | 201 | */ |
200 | loader.media = function(playlist) { | 202 | loader.media = function(playlist) { |
201 | var startingState = loader.state, mediaChange; | 203 | let startingState = loader.state; |
204 | let mediaChange; | ||
202 | // getter | 205 | // getter |
203 | if (!playlist) { | 206 | if (!playlist) { |
204 | return loader.media_; | 207 | return loader.media_; |
... | @@ -258,9 +261,9 @@ | ... | @@ -258,9 +261,9 @@ |
258 | } | 261 | } |
259 | 262 | ||
260 | // request the new playlist | 263 | // request the new playlist |
261 | request = xhr({ | 264 | request = XhrModule({ |
262 | uri: resolveUrl(loader.master.uri, playlist.uri), | 265 | uri: resolveUrl(loader.master.uri, playlist.uri), |
263 | withCredentials: withCredentials | 266 | withCredentials |
264 | }, function(error, request) { | 267 | }, function(error, request) { |
265 | if (error) { | 268 | if (error) { |
266 | return playlistRequestError(request, playlist.uri, startingState); | 269 | return playlistRequestError(request, playlist.uri, startingState); |
... | @@ -295,9 +298,9 @@ | ... | @@ -295,9 +298,9 @@ |
295 | } | 298 | } |
296 | 299 | ||
297 | loader.state = 'HAVE_CURRENT_METADATA'; | 300 | loader.state = 'HAVE_CURRENT_METADATA'; |
298 | request = xhr({ | 301 | request = XhrModule({ |
299 | uri: resolveUrl(loader.master.uri, loader.media().uri), | 302 | uri: resolveUrl(loader.master.uri, loader.media().uri), |
300 | withCredentials: withCredentials | 303 | withCredentials |
301 | }, function(error, request) { | 304 | }, function(error, request) { |
302 | if (error) { | 305 | if (error) { |
303 | return playlistRequestError(request, loader.media().uri); | 306 | return playlistRequestError(request, loader.media().uri); |
... | @@ -307,11 +310,12 @@ | ... | @@ -307,11 +310,12 @@ |
307 | }); | 310 | }); |
308 | 311 | ||
309 | // request the specified URL | 312 | // request the specified URL |
310 | request = xhr({ | 313 | request = XhrModule({ |
311 | uri: srcUrl, | 314 | uri: srcUrl, |
312 | withCredentials: withCredentials | 315 | withCredentials |
313 | }, function(error, req) { | 316 | }, function(error, req) { |
314 | var parser, i; | 317 | let parser; |
318 | let i; | ||
315 | 319 | ||
316 | // clear the loader's request reference | 320 | // clear the loader's request reference |
317 | request = null; | 321 | request = null; |
... | @@ -321,12 +325,13 @@ | ... | @@ -321,12 +325,13 @@ |
321 | status: req.status, | 325 | status: req.status, |
322 | message: 'HLS playlist request error at URL: ' + srcUrl, | 326 | message: 'HLS playlist request error at URL: ' + srcUrl, |
323 | responseText: req.responseText, | 327 | responseText: req.responseText, |
324 | code: 2 // MEDIA_ERR_NETWORK | 328 | // MEDIA_ERR_NETWORK |
329 | code: 2 | ||
325 | }; | 330 | }; |
326 | return loader.trigger('error'); | 331 | return loader.trigger('error'); |
327 | } | 332 | } |
328 | 333 | ||
329 | parser = new videojs.m3u8.Parser(); | 334 | parser = new m3u8.Parser(); |
330 | parser.push(req.responseText); | 335 | parser.push(req.responseText); |
331 | parser.end(); | 336 | parser.end(); |
332 | 337 | ||
... | @@ -365,16 +370,16 @@ | ... | @@ -365,16 +370,16 @@ |
365 | haveMetadata(req, srcUrl); | 370 | haveMetadata(req, srcUrl); |
366 | return loader.trigger('loadedmetadata'); | 371 | return loader.trigger('loadedmetadata'); |
367 | }); | 372 | }); |
368 | }; | 373 | } |
369 | PlaylistLoader.prototype = new videojs.Hls.Stream(); | ||
370 | |||
371 | /** | 374 | /** |
372 | * Update the PlaylistLoader state to reflect the changes in an | 375 | * Update the PlaylistLoader state to reflect the changes in an |
373 | * update to the current media playlist. | 376 | * update to the current media playlist. |
374 | * @param update {object} the updated media playlist object | 377 | * @param update {object} the updated media playlist object |
375 | */ | 378 | */ |
376 | PlaylistLoader.prototype.updateMediaPlaylist_ = function(update) { | 379 | updateMediaPlaylist_(update) { |
377 | var outdated, i, segment; | 380 | let outdated; |
381 | let i; | ||
382 | let segment; | ||
378 | 383 | ||
379 | outdated = this.media_; | 384 | outdated = this.media_; |
380 | this.media_ = this.master.playlists[update.uri]; | 385 | this.media_ = this.master.playlists[update.uri]; |
... | @@ -432,7 +437,7 @@ | ... | @@ -432,7 +437,7 @@ |
432 | } | 437 | } |
433 | this.expired_ += segment.duration; | 438 | this.expired_ += segment.duration; |
434 | } | 439 | } |
435 | }; | 440 | } |
436 | 441 | ||
437 | /** | 442 | /** |
438 | * Determine the index of the segment that contains a specified | 443 | * Determine the index of the segment that contains a specified |
... | @@ -452,17 +457,16 @@ | ... | @@ -452,17 +457,16 @@ |
452 | * value will be clamped to the index of the segment containing the | 457 | * value will be clamped to the index of the segment containing the |
453 | * closest playback position that is currently available. | 458 | * closest playback position that is currently available. |
454 | */ | 459 | */ |
455 | PlaylistLoader.prototype.getMediaIndexForTime_ = function(time) { | 460 | getMediaIndexForTime_(time) { |
456 | var | 461 | let i; |
457 | i, | 462 | let segment; |
458 | segment, | 463 | let originalTime = time; |
459 | originalTime = time, | 464 | let numSegments = this.media_.segments.length; |
460 | numSegments = this.media_.segments.length, | 465 | let lastSegment = numSegments - 1; |
461 | lastSegment = numSegments - 1, | 466 | let startIndex; |
462 | startIndex, | 467 | let endIndex; |
463 | endIndex, | 468 | let knownStart; |
464 | knownStart, | 469 | let knownEnd; |
465 | knownEnd; | ||
466 | 470 | ||
467 | if (!this.media_) { | 471 | if (!this.media_) { |
468 | return 0; | 472 | return 0; |
... | @@ -558,7 +562,5 @@ | ... | @@ -558,7 +562,5 @@ |
558 | // the one most likely to tell us something about the timeline | 562 | // the one most likely to tell us something about the timeline |
559 | return lastSegment; | 563 | return lastSegment; |
560 | } | 564 | } |
561 | }; | 565 | } |
562 | 566 | } | |
563 | videojs.Hls.PlaylistLoader = PlaylistLoader; | ||
564 | })(window, window.videojs); | ... | ... |
1 | /** | 1 | /** |
2 | * Playlist related utilities. | 2 | * Playlist related utilities. |
3 | */ | 3 | */ |
4 | (function(window, videojs) { | 4 | import {createTimeRange} from 'video.js'; |
5 | 'use strict'; | ||
6 | 5 | ||
7 | var duration, intervalDuration, backwardDuration, forwardDuration, seekable; | 6 | const backwardDuration = function(playlist, endSequence) { |
8 | 7 | let result = 0; | |
9 | backwardDuration = function(playlist, endSequence) { | 8 | let i = endSequence - playlist.mediaSequence; |
10 | var result = 0, segment, i; | ||
11 | |||
12 | i = endSequence - playlist.mediaSequence; | ||
13 | // if a start time is available for segment immediately following | 9 | // if a start time is available for segment immediately following |
14 | // the interval, use it | 10 | // the interval, use it |
15 | segment = playlist.segments[i]; | 11 | let segment = playlist.segments[i]; |
12 | |||
16 | // Walk backward until we find the latest segment with timeline | 13 | // Walk backward until we find the latest segment with timeline |
17 | // information that is earlier than endSequence | 14 | // information that is earlier than endSequence |
18 | if (segment) { | 15 | if (segment) { |
19 | if (segment.start !== undefined) { | 16 | if (typeof segment.start !== 'undefined') { |
20 | return { result: segment.start, precise: true }; | 17 | return { result: segment.start, precise: true }; |
21 | } | 18 | } |
22 | if (segment.end !== undefined) { | 19 | if (typeof segment.end !== 'undefined') { |
23 | return { | 20 | return { |
24 | result: segment.end - segment.duration, | 21 | result: segment.end - segment.duration, |
25 | precise: true | 22 | precise: true |
... | @@ -28,28 +25,29 @@ | ... | @@ -28,28 +25,29 @@ |
28 | } | 25 | } |
29 | while (i--) { | 26 | while (i--) { |
30 | segment = playlist.segments[i]; | 27 | segment = playlist.segments[i]; |
31 | if (segment.end !== undefined) { | 28 | if (typeof segment.end !== 'undefined') { |
32 | return { result: result + segment.end, precise: true }; | 29 | return { result: result + segment.end, precise: true }; |
33 | } | 30 | } |
34 | 31 | ||
35 | result += segment.duration; | 32 | result += segment.duration; |
36 | 33 | ||
37 | if (segment.start !== undefined) { | 34 | if (typeof segment.start !== 'undefined') { |
38 | return { result: result + segment.start, precise: true }; | 35 | return { result: result + segment.start, precise: true }; |
39 | } | 36 | } |
40 | } | 37 | } |
41 | return { result: result, precise: false }; | 38 | return { result, precise: false }; |
42 | }; | 39 | }; |
43 | |||
44 | forwardDuration = function(playlist, endSequence) { | ||
45 | var result = 0, segment, i; | ||
46 | 40 | ||
47 | i = endSequence - playlist.mediaSequence; | 41 | const forwardDuration = function(playlist, endSequence) { |
42 | let result = 0; | ||
43 | let segment; | ||
44 | let i = endSequence - playlist.mediaSequence; | ||
48 | // Walk forward until we find the earliest segment with timeline | 45 | // Walk forward until we find the earliest segment with timeline |
49 | // information | 46 | // information |
47 | |||
50 | for (; i < playlist.segments.length; i++) { | 48 | for (; i < playlist.segments.length; i++) { |
51 | segment = playlist.segments[i]; | 49 | segment = playlist.segments[i]; |
52 | if (segment.start !== undefined) { | 50 | if (typeof segment.start !== 'undefined') { |
53 | return { | 51 | return { |
54 | result: segment.start - result, | 52 | result: segment.start - result, |
55 | precise: true | 53 | precise: true |
... | @@ -58,7 +56,7 @@ | ... | @@ -58,7 +56,7 @@ |
58 | 56 | ||
59 | result += segment.duration; | 57 | result += segment.duration; |
60 | 58 | ||
61 | if (segment.end !== undefined) { | 59 | if (typeof segment.end !== 'undefined') { |
62 | return { | 60 | return { |
63 | result: segment.end - result, | 61 | result: segment.end - result, |
64 | precise: true | 62 | precise: true |
... | @@ -68,9 +66,9 @@ | ... | @@ -68,9 +66,9 @@ |
68 | } | 66 | } |
69 | // indicate we didn't find a useful duration estimate | 67 | // indicate we didn't find a useful duration estimate |
70 | return { result: -1, precise: false }; | 68 | return { result: -1, precise: false }; |
71 | }; | 69 | }; |
72 | 70 | ||
73 | /** | 71 | /** |
74 | * Calculate the media duration from the segments associated with a | 72 | * Calculate the media duration from the segments associated with a |
75 | * playlist. The duration of a subinterval of the available segments | 73 | * playlist. The duration of a subinterval of the available segments |
76 | * may be calculated by specifying an end index. | 74 | * may be calculated by specifying an end index. |
... | @@ -81,10 +79,11 @@ | ... | @@ -81,10 +79,11 @@ |
81 | * @return {number} the duration between the first available segment | 79 | * @return {number} the duration between the first available segment |
82 | * and end index. | 80 | * and end index. |
83 | */ | 81 | */ |
84 | intervalDuration = function(playlist, endSequence) { | 82 | const intervalDuration = function(playlist, endSequence) { |
85 | var backward, forward; | 83 | let backward; |
84 | let forward; | ||
86 | 85 | ||
87 | if (endSequence === undefined) { | 86 | if (typeof endSequence === 'undefined') { |
88 | endSequence = playlist.mediaSequence + playlist.segments.length; | 87 | endSequence = playlist.mediaSequence + playlist.segments.length; |
89 | } | 88 | } |
90 | 89 | ||
... | @@ -112,9 +111,9 @@ | ... | @@ -112,9 +111,9 @@ |
112 | 111 | ||
113 | // return the less-precise, playlist-based duration estimate | 112 | // return the less-precise, playlist-based duration estimate |
114 | return backward.result; | 113 | return backward.result; |
115 | }; | 114 | }; |
116 | 115 | ||
117 | /** | 116 | /** |
118 | * Calculates the duration of a playlist. If a start and end index | 117 | * Calculates the duration of a playlist. If a start and end index |
119 | * are specified, the duration will be for the subset of the media | 118 | * are specified, the duration will be for the subset of the media |
120 | * timeline between those two indices. The total duration for live | 119 | * timeline between those two indices. The total duration for live |
... | @@ -129,18 +128,18 @@ | ... | @@ -129,18 +128,18 @@ |
129 | * @return {number} the duration between the start index and end | 128 | * @return {number} the duration between the start index and end |
130 | * index. | 129 | * index. |
131 | */ | 130 | */ |
132 | duration = function(playlist, endSequence, includeTrailingTime) { | 131 | export const duration = function(playlist, endSequence, includeTrailingTime) { |
133 | if (!playlist) { | 132 | if (!playlist) { |
134 | return 0; | 133 | return 0; |
135 | } | 134 | } |
136 | 135 | ||
137 | if (includeTrailingTime === undefined) { | 136 | if (typeof includeTrailingTime === 'undefined') { |
138 | includeTrailingTime = true; | 137 | includeTrailingTime = true; |
139 | } | 138 | } |
140 | 139 | ||
141 | // if a slice of the total duration is not requested, use | 140 | // if a slice of the total duration is not requested, use |
142 | // playlist-level duration indicators when they're present | 141 | // playlist-level duration indicators when they're present |
143 | if (endSequence === undefined) { | 142 | if (typeof endSequence === 'undefined') { |
144 | // if present, use the duration specified in the playlist | 143 | // if present, use the duration specified in the playlist |
145 | if (playlist.totalDuration) { | 144 | if (playlist.totalDuration) { |
146 | return playlist.totalDuration; | 145 | return playlist.totalDuration; |
... | @@ -156,9 +155,9 @@ | ... | @@ -156,9 +155,9 @@ |
156 | return intervalDuration(playlist, | 155 | return intervalDuration(playlist, |
157 | endSequence, | 156 | endSequence, |
158 | includeTrailingTime); | 157 | includeTrailingTime); |
159 | }; | 158 | }; |
160 | 159 | ||
161 | /** | 160 | /** |
162 | * Calculates the interval of time that is currently seekable in a | 161 | * Calculates the interval of time that is currently seekable in a |
163 | * playlist. The returned time ranges are relative to the earliest | 162 | * playlist. The returned time ranges are relative to the earliest |
164 | * moment in the specified playlist that is still available. A full | 163 | * moment in the specified playlist that is still available. A full |
... | @@ -169,16 +168,17 @@ | ... | @@ -169,16 +168,17 @@ |
169 | * @return {TimeRanges} the periods of time that are valid targets | 168 | * @return {TimeRanges} the periods of time that are valid targets |
170 | * for seeking | 169 | * for seeking |
171 | */ | 170 | */ |
172 | seekable = function(playlist) { | 171 | export const seekable = function(playlist) { |
173 | var start, end; | 172 | let start; |
173 | let end; | ||
174 | 174 | ||
175 | // without segments, there are no seekable ranges | 175 | // without segments, there are no seekable ranges |
176 | if (!playlist.segments) { | 176 | if (!playlist.segments) { |
177 | return videojs.createTimeRange(); | 177 | return createTimeRange(); |
178 | } | 178 | } |
179 | // when the playlist is complete, the entire duration is seekable | 179 | // when the playlist is complete, the entire duration is seekable |
180 | if (playlist.endList) { | 180 | if (playlist.endList) { |
181 | return videojs.createTimeRange(0, duration(playlist)); | 181 | return createTimeRange(0, duration(playlist)); |
182 | } | 182 | } |
183 | 183 | ||
184 | // live playlists should not expose three segment durations worth | 184 | // live playlists should not expose three segment durations worth |
... | @@ -186,13 +186,13 @@ | ... | @@ -186,13 +186,13 @@ |
186 | // https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-6.3.3 | 186 | // https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-6.3.3 |
187 | start = intervalDuration(playlist, playlist.mediaSequence); | 187 | start = intervalDuration(playlist, playlist.mediaSequence); |
188 | end = intervalDuration(playlist, | 188 | end = intervalDuration(playlist, |
189 | playlist.mediaSequence + Math.max(0, playlist.segments.length - 3)); | 189 | playlist.mediaSequence + |
190 | return videojs.createTimeRange(start, end); | 190 | Math.max(0, playlist.segments.length - 3)); |
191 | }; | 191 | return createTimeRange(start, end); |
192 | 192 | }; | |
193 | // exports | 193 | |
194 | videojs.Hls.Playlist = { | 194 | // exports |
195 | duration: duration, | 195 | export default { |
196 | seekable: seekable | 196 | duration, |
197 | }; | 197 | seekable |
198 | })(window, window.videojs); | 198 | }; | ... | ... |
src/resolve-url.js
0 → 100644
1 | import document from 'global/document'; | ||
2 | /* eslint-disable max-len */ | ||
3 | /** | ||
4 | * Constructs a new URI by interpreting a path relative to another | ||
5 | * URI. | ||
6 | * @param basePath {string} a relative or absolute URI | ||
7 | * @param path {string} a path part to combine with the base | ||
8 | * @return {string} a URI that is equivalent to composing `base` | ||
9 | * with `path` | ||
10 | * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue | ||
11 | */ | ||
12 | /* eslint-enable max-len */ | ||
13 | const resolveUrl = function(basePath, path) { | ||
14 | // use the base element to get the browser to handle URI resolution | ||
15 | let oldBase = document.querySelector('base'); | ||
16 | let docHead = document.querySelector('head'); | ||
17 | let a = document.createElement('a'); | ||
18 | let base = oldBase; | ||
19 | let oldHref; | ||
20 | let result; | ||
21 | |||
22 | // prep the document | ||
23 | if (oldBase) { | ||
24 | oldHref = oldBase.href; | ||
25 | } else { | ||
26 | base = docHead.appendChild(document.createElement('base')); | ||
27 | } | ||
28 | |||
29 | base.href = basePath; | ||
30 | a.href = path; | ||
31 | result = a.href; | ||
32 | |||
33 | // clean up | ||
34 | if (oldBase) { | ||
35 | oldBase.href = oldHref; | ||
36 | } else { | ||
37 | docHead.removeChild(base); | ||
38 | } | ||
39 | return result; | ||
40 | }; | ||
41 | |||
42 | export default resolveUrl; |
... | @@ -2,6 +2,10 @@ import m3u8 from './m3u8'; | ... | @@ -2,6 +2,10 @@ import m3u8 from './m3u8'; |
2 | import Stream from './stream'; | 2 | import Stream from './stream'; |
3 | import videojs from 'video.js'; | 3 | import videojs from 'video.js'; |
4 | import {Decrypter, decrypt, AsyncStream} from './decrypter'; | 4 | import {Decrypter, decrypt, AsyncStream} from './decrypter'; |
5 | import Playlist from './playlist'; | ||
6 | import PlaylistLoader from './playlist-loader'; | ||
7 | import xhr from './xhr'; | ||
8 | |||
5 | 9 | ||
6 | if(typeof window.videojs.Hls === 'undefined') { | 10 | if(typeof window.videojs.Hls === 'undefined') { |
7 | videojs.Hls = {}; | 11 | videojs.Hls = {}; |
... | @@ -11,3 +15,6 @@ videojs.m3u8 = m3u8; | ... | @@ -11,3 +15,6 @@ videojs.m3u8 = m3u8; |
11 | videojs.Hls.decrypt = decrypt; | 15 | videojs.Hls.decrypt = decrypt; |
12 | videojs.Hls.Decrypter = Decrypter; | 16 | videojs.Hls.Decrypter = Decrypter; |
13 | videojs.Hls.AsyncStream = AsyncStream; | 17 | videojs.Hls.AsyncStream = AsyncStream; |
18 | videojs.Hls.xhr = xhr; | ||
19 | videojs.Hls.Playlist = Playlist; | ||
20 | videojs.Hls.PlaylistLoader = PlaylistLoader; | ... | ... |
1 | (function(videojs) { | 1 | /** |
2 | 'use strict'; | ||
3 | |||
4 | /** | ||
5 | * A wrapper for videojs.xhr that tracks bandwidth. | 2 | * A wrapper for videojs.xhr that tracks bandwidth. |
6 | */ | 3 | */ |
7 | videojs.Hls.xhr = function(options, callback) { | 4 | import {xhr as videojsXHR, mergeOptions} from 'video.js'; |
5 | const xhr = function(options, callback) { | ||
8 | // Add a default timeout for all hls requests | 6 | // Add a default timeout for all hls requests |
9 | options = videojs.mergeOptions({ | 7 | options = mergeOptions({ |
10 | timeout: 45e3 | 8 | timeout: 45e3 |
11 | }, options); | 9 | }, options); |
12 | 10 | ||
13 | var request = videojs.xhr(options, function(error, response) { | 11 | let request = videojsXHR(options, function(error, response) { |
14 | if (!error && request.response) { | 12 | if (!error && request.response) { |
15 | request.responseTime = (new Date()).getTime(); | 13 | request.responseTime = (new Date()).getTime(); |
16 | request.roundTripTime = request.responseTime - request.requestTime; | 14 | request.roundTripTime = request.responseTime - request.requestTime; |
17 | request.bytesReceived = request.response.byteLength || request.response.length; | 15 | request.bytesReceived = request.response.byteLength || request.response.length; |
18 | if (!request.bandwidth) { | 16 | if (!request.bandwidth) { |
19 | request.bandwidth = Math.floor((request.bytesReceived / request.roundTripTime) * 8 * 1000); | 17 | request.bandwidth = |
18 | Math.floor((request.bytesReceived / request.roundTripTime) * 8 * 1000); | ||
20 | } | 19 | } |
21 | } | 20 | } |
22 | 21 | ||
23 | // videojs.xhr now uses a specific code on the error object to signal that a request has | 22 | // videojs.xhr now uses a specific code |
23 | // on the error object to signal that a request has | ||
24 | // timed out errors of setting a boolean on the request object | 24 | // timed out errors of setting a boolean on the request object |
25 | if (error || request.timedout) { | 25 | if (error || request.timedout) { |
26 | request.timedout = request.timedout || (error.code === 'ETIMEDOUT'); | 26 | request.timedout = request.timedout || (error.code === 'ETIMEDOUT'); |
... | @@ -44,5 +44,6 @@ | ... | @@ -44,5 +44,6 @@ |
44 | 44 | ||
45 | request.requestTime = (new Date()).getTime(); | 45 | request.requestTime = (new Date()).getTime(); |
46 | return request; | 46 | return request; |
47 | }; | 47 | }; |
48 | })(window.videojs); | 48 | |
49 | export default xhr; | ... | ... |
... | @@ -16,16 +16,11 @@ | ... | @@ -16,16 +16,11 @@ |
16 | <script src="/node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> | 16 | <script src="/node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script> |
17 | 17 | ||
18 | <script src="/src/videojs-contrib-hls.js"></script> | 18 | <script src="/src/videojs-contrib-hls.js"></script> |
19 | <script src="/src/xhr.js"></script> | ||
20 | <script src="/dist/videojs-contrib-hls.js"></script> | 19 | <script src="/dist/videojs-contrib-hls.js"></script> |
21 | <script src="/src/playlist.js"></script> | ||
22 | <script src="/src/playlist-loader.js"></script> | ||
23 | <script src="/src/bin-utils.js"></script> | 20 | <script src="/src/bin-utils.js"></script> |
24 | 21 | ||
25 | <script src="/test/videojs-contrib-hls.test.js"></script> | 22 | <script src="/test/videojs-contrib-hls.test.js"></script> |
26 | <script src="/dist-test/videojs-contrib-hls.js"></script> | 23 | <script src="/dist-test/videojs-contrib-hls.js"></script> |
27 | <script src="/test/playlist.test.js"></script> | ||
28 | <script src="/test/playlist-loader.test.js"></script> | ||
29 | 24 | ||
30 | </body> | 25 | </body> |
31 | </html> | 26 | </html> | ... | ... |
... | @@ -16,11 +16,8 @@ var DEFAULTS = { | ... | @@ -16,11 +16,8 @@ var DEFAULTS = { |
16 | 16 | ||
17 | // these two stub old functionality | 17 | // these two stub old functionality |
18 | 'src/videojs-contrib-hls.js', | 18 | 'src/videojs-contrib-hls.js', |
19 | 'src/xhr.js', | ||
20 | 'dist/videojs-contrib-hls.js', | 19 | 'dist/videojs-contrib-hls.js', |
21 | 20 | ||
22 | 'src/playlist.js', | ||
23 | 'src/playlist-loader.js', | ||
24 | 'src/bin-utils.js', | 21 | 'src/bin-utils.js', |
25 | 22 | ||
26 | 'test/stub.test.js', | 23 | 'test/stub.test.js', |
... | @@ -45,7 +42,7 @@ var DEFAULTS = { | ... | @@ -45,7 +42,7 @@ var DEFAULTS = { |
45 | ], | 42 | ], |
46 | 43 | ||
47 | preprocessors: { | 44 | preprocessors: { |
48 | 'test/{decrypter,stub,m3u8}.test.js': ['browserify'] | 45 | 'test/{playlist*,decrypter,stub,m3u8}.test.js': ['browserify'] |
49 | }, | 46 | }, |
50 | 47 | ||
51 | reporters: ['dots'], | 48 | reporters: ['dots'], | ... | ... |
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
-
Please register or sign in to post a comment