1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

update components

This commit is contained in:
Luke Pulverenti 2016-06-17 09:11:34 -04:00
parent 8df5412c5c
commit 8f05a7a53d
15 changed files with 131 additions and 159 deletions

View file

@ -15,12 +15,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.4.51", "version": "1.4.52",
"_release": "1.4.51", "_release": "1.4.52",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.4.51", "tag": "1.4.52",
"commit": "90b14ccc0e927221ab1d6c7556d1fadccf3876b9" "commit": "80aad0c646abb9e92cdf3caea1340ce81c9ab38d"
}, },
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "^1.2.0", "_target": "^1.2.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "hls.js", "name": "hls.js",
"version": "0.5.36", "version": "0.5.39",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "Media Source Extension - HLS library, by/for Dailymotion", "description": "Media Source Extension - HLS library, by/for Dailymotion",
"homepage": "https://github.com/dailymotion/hls.js", "homepage": "https://github.com/dailymotion/hls.js",
@ -16,11 +16,11 @@
"test", "test",
"tests" "tests"
], ],
"_release": "0.5.36", "_release": "0.5.39",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v0.5.36", "tag": "v0.5.39",
"commit": "a39814dc1e5be2516518a30edf9f1629e05dea27" "commit": "4a4a95907809da3c7391740000804a9b95355dce"
}, },
"_source": "git://github.com/dailymotion/hls.js.git", "_source": "git://github.com/dailymotion/hls.js.git",
"_target": "~0.5.7", "_target": "~0.5.7",

View file

@ -1,6 +1,6 @@
{ {
"name": "hls.js", "name": "hls.js",
"version": "0.5.36", "version": "0.5.39",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "Media Source Extension - HLS library, by/for Dailymotion", "description": "Media Source Extension - HLS library, by/for Dailymotion",
"homepage": "https://github.com/dailymotion/hls.js", "homepage": "https://github.com/dailymotion/hls.js",

View file

@ -435,7 +435,9 @@ var AbrController = function (_EventHandler) {
if (!this.timer) { if (!this.timer) {
this.timer = setInterval(this.onCheck, 100); this.timer = setInterval(this.onCheck, 100);
} }
this.fragCurrent = data.frag; var frag = data.frag;
frag.trequest = performance.now();
this.fragCurrent = frag;
} }
}, { }, {
key: 'abandonRulesCheck', key: 'abandonRulesCheck',
@ -461,12 +463,14 @@ var AbrController = function (_EventHandler) {
var requestDelay = performance.now() - frag.trequest; var requestDelay = performance.now() - frag.trequest;
// monitor fragment load progress after half of expected fragment duration,to stabilize bitrate // monitor fragment load progress after half of expected fragment duration,to stabilize bitrate
if (requestDelay > 500 * frag.duration) { if (requestDelay > 500 * frag.duration) {
var loadRate = Math.max(1, frag.loaded * 1000 / requestDelay); // byte/s; at least 1 byte/s to avoid division by zero var levels = hls.levels,
if (frag.expectedLen < frag.loaded) { loadRate = Math.max(1, frag.loaded * 1000 / requestDelay),
frag.expectedLen = frag.loaded; // byte/s; at least 1 byte/s to avoid division by zero
} // compute expected fragment length using frag duration and level bitrate. also ensure that expected len is gte than already loaded size
expectedLen = Math.max(frag.loaded, Math.round(frag.duration * levels[frag.level].bitrate / 8));
var pos = v.currentTime; var pos = v.currentTime;
var fragLoadedDelay = (frag.expectedLen - frag.loaded) / loadRate; var fragLoadedDelay = (expectedLen - frag.loaded) / loadRate;
var bufferStarvationDelay = _bufferHelper2.default.bufferInfo(v, pos, hls.config.maxBufferHole).end - pos; var bufferStarvationDelay = _bufferHelper2.default.bufferInfo(v, pos, hls.config.maxBufferHole).end - pos;
// consider emergency switch down only if we have less than 2 frag buffered AND // consider emergency switch down only if we have less than 2 frag buffered AND
// time to finish loading current fragment is bigger than buffer starvation delay // time to finish loading current fragment is bigger than buffer starvation delay
@ -480,7 +484,7 @@ var AbrController = function (_EventHandler) {
// compute time to load next fragment at lower level // compute time to load next fragment at lower level
// 0.8 : consider only 80% of current bw to be conservative // 0.8 : consider only 80% of current bw to be conservative
// 8 = bits per byte (bps/Bps) // 8 = bits per byte (bps/Bps)
fragLevelNextLoadedDelay = frag.duration * hls.levels[nextLoadLevel].bitrate / (8 * 0.8 * loadRate); fragLevelNextLoadedDelay = frag.duration * levels[nextLoadLevel].bitrate / (8 * 0.8 * loadRate);
_logger.logger.log('fragLoadedDelay/bufferStarvationDelay/fragLevelNextLoadedDelay[' + nextLoadLevel + '] :' + fragLoadedDelay.toFixed(1) + '/' + bufferStarvationDelay.toFixed(1) + '/' + fragLevelNextLoadedDelay.toFixed(1)); _logger.logger.log('fragLoadedDelay/bufferStarvationDelay/fragLevelNextLoadedDelay[' + nextLoadLevel + '] :' + fragLoadedDelay.toFixed(1) + '/' + bufferStarvationDelay.toFixed(1) + '/' + fragLevelNextLoadedDelay.toFixed(1));
if (fragLevelNextLoadedDelay < bufferStarvationDelay) { if (fragLevelNextLoadedDelay < bufferStarvationDelay) {
// we found a lower level that be rebuffering free with current estimated bw ! // we found a lower level that be rebuffering free with current estimated bw !
@ -1257,7 +1261,7 @@ var EwmaBandWidthEstimator = function () {
}, { }, {
key: 'getEstimate', key: 'getEstimate',
value: function getEstimate() { value: function getEstimate() {
if (this.fast_.getTotalWeight() < this.minWeight_) { if (!this.fast_ || this.fast_.getTotalWeight() < this.minWeight_) {
return this.defaultEstimate_; return this.defaultEstimate_;
} }
//console.log('slow estimate:'+ Math.round(this.slow_.getEstimate())); //console.log('slow estimate:'+ Math.round(this.slow_.getEstimate()));
@ -1868,9 +1872,12 @@ var StreamController = function (_EventHandler) {
if (bufferEnd < Math.max(start, end - maxLatency)) { if (bufferEnd < Math.max(start, end - maxLatency)) {
var targetLatency = config.liveSyncDuration !== undefined ? config.liveSyncDuration : config.liveSyncDurationCount * levelDetails.targetduration; var targetLatency = config.liveSyncDuration !== undefined ? config.liveSyncDuration : config.liveSyncDurationCount * levelDetails.targetduration;
this.seekAfterBuffered = start + Math.max(0, levelDetails.totalduration - targetLatency); var liveSyncPosition = start + Math.max(0, levelDetails.totalduration - targetLatency);
_logger.logger.log('buffer end: ' + bufferEnd + ' is located too far from the end of live sliding playlist, media position will be reseted to: ' + this.seekAfterBuffered.toFixed(3)); _logger.logger.log('buffer end: ' + bufferEnd + ' is located too far from the end of live sliding playlist, reset currentTime to : ' + liveSyncPosition.toFixed(3));
bufferEnd = this.seekAfterBuffered; bufferEnd = liveSyncPosition;
if (media && media.readyState && media.duration > liveSyncPosition) {
media.currentTime = liveSyncPosition;
}
} }
// if end of buffer greater than live edge, don't load any fragment // if end of buffer greater than live edge, don't load any fragment
@ -1976,11 +1983,6 @@ var StreamController = function (_EventHandler) {
hls.trigger(_events2.default.KEY_LOADING, { frag: frag }); hls.trigger(_events2.default.KEY_LOADING, { frag: frag });
} else { } else {
_logger.logger.log('Loading ' + frag.sn + ' of [' + levelDetails.startSN + ' ,' + levelDetails.endSN + '],level ' + level + ', currentTime:' + pos + ',bufferEnd:' + bufferEnd.toFixed(3)); _logger.logger.log('Loading ' + frag.sn + ' of [' + levelDetails.startSN + ' ,' + levelDetails.endSN + '],level ' + level + ', currentTime:' + pos + ',bufferEnd:' + bufferEnd.toFixed(3));
frag.autoLevel = hls.autoLevelEnabled;
if (this.levels.length > 1) {
frag.expectedLen = Math.round(frag.duration * this.levels[level].bitrate / 8);
frag.trequest = performance.now();
}
// ensure that we are not reloading the same fragments in loop ... // ensure that we are not reloading the same fragments in loop ...
if (this.fragLoadIdx !== undefined) { if (this.fragLoadIdx !== undefined) {
this.fragLoadIdx++; this.fragLoadIdx++;
@ -2001,6 +2003,7 @@ var StreamController = function (_EventHandler) {
frag.loadIdx = this.fragLoadIdx; frag.loadIdx = this.fragLoadIdx;
this.fragCurrent = frag; this.fragCurrent = frag;
this.startFragRequested = true; this.startFragRequested = true;
frag.autoLevel = hls.autoLevelEnabled;
hls.trigger(_events2.default.FRAG_LOADING, { frag: frag }); hls.trigger(_events2.default.FRAG_LOADING, { frag: frag });
this.state = State.FRAG_LOADING; this.state = State.FRAG_LOADING;
} }
@ -2665,36 +2668,32 @@ var StreamController = function (_EventHandler) {
key: '_checkBuffer', key: '_checkBuffer',
value: function _checkBuffer() { value: function _checkBuffer() {
var media = this.media; var media = this.media;
if (media) { // if ready state different from HAVE_NOTHING (numeric value 0), we are allowed to seek
// compare readyState if (media && media.readyState) {
var readyState = media.readyState; var currentTime = media.currentTime,
// if ready state different from HAVE_NOTHING (numeric value 0), we are allowed to seek buffered = media.buffered;
if (readyState) { // adjust currentTime to start position on loaded metadata
var targetSeekPosition, currentTime; if (!this.loadedmetadata && buffered.length) {
// if seek after buffered defined, let's seek if within acceptable range this.loadedmetadata = true;
var seekAfterBuffered = this.seekAfterBuffered; // only adjust currentTime if startPosition not equal to 0
if (seekAfterBuffered) { var startPosition = this.startPosition;
if (media.duration >= seekAfterBuffered) { // if currentTime === 0 AND not matching with expected startPosition
targetSeekPosition = seekAfterBuffered; if (!currentTime && currentTime !== startPosition) {
this.seekAfterBuffered = undefined; if (startPosition) {
} _logger.logger.log('target start position:' + startPosition);
} else { // at that stage, there should be only one buffered range, as we reach that code after first fragment has been
currentTime = media.currentTime; var bufferStart = buffered.start(0),
var loadedmetadata = this.loadedmetadata; bufferEnd = buffered.end(0);
// if startPosition not buffered, let's seek to buffered.start(0)
// adjust currentTime to start position on loaded metadata if (startPosition < bufferStart || startPosition > bufferEnd) {
if (!loadedmetadata && media.buffered.length) { startPosition = bufferStart;
this.loadedmetadata = true; _logger.logger.log('target start position not buffered, seek to buffered.start(0) ' + bufferStart);
// only adjust currentTime if not equal to 0
if (!currentTime && currentTime !== this.startPosition) {
targetSeekPosition = this.startPosition;
} }
_logger.logger.log('adjust currentTime from ' + currentTime + ' to ' + startPosition);
media.currentTime = startPosition;
} }
} }
if (targetSeekPosition) { } else {
currentTime = targetSeekPosition;
_logger.logger.log('target seek position:' + targetSeekPosition);
}
var bufferInfo = _bufferHelper2.default.bufferInfo(media, currentTime, 0), var bufferInfo = _bufferHelper2.default.bufferInfo(media, currentTime, 0),
expectedPlaying = !(media.paused || // not playing when media is paused expectedPlaying = !(media.paused || // not playing when media is paused
media.ended || // not playing when media is ended media.ended || // not playing when media is ended
@ -2709,8 +2708,7 @@ var StreamController = function (_EventHandler) {
_logger.logger.log('playback not stuck anymore @' + currentTime); _logger.logger.log('playback not stuck anymore @' + currentTime);
} }
// check buffer upfront // check buffer upfront
// if less than jumpThreshold second is buffered, and media is expected to play but playhead is not moving, // if less than jumpThreshold second is buffered, let's check in more details
// and we have a new buffer range available upfront, let's seek to that one
if (expectedPlaying && bufferInfo.len <= jumpThreshold) { if (expectedPlaying && bufferInfo.len <= jumpThreshold) {
if (playheadMoving) { if (playheadMoving) {
// playhead moving // playhead moving
@ -2727,7 +2725,7 @@ var StreamController = function (_EventHandler) {
this.seekHoleNudgeDuration += this.config.seekHoleNudgeDuration; this.seekHoleNudgeDuration += this.config.seekHoleNudgeDuration;
} }
} }
// if we are below threshold, try to jump if next buffer range is close // if we are below threshold, try to jump to start of next buffer range if close
if (bufferInfo.len <= jumpThreshold) { if (bufferInfo.len <= jumpThreshold) {
// no buffer available @ currentTime, check if next buffer is close (within a config.maxSeekHole second range) // no buffer available @ currentTime, check if next buffer is close (within a config.maxSeekHole second range)
var nextBufferStart = bufferInfo.nextStart, var nextBufferStart = bufferInfo.nextStart,
@ -2741,19 +2739,6 @@ var StreamController = function (_EventHandler) {
this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_SEEK_OVER_HOLE, fatal: false, hole: hole }); this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_SEEK_OVER_HOLE, fatal: false, hole: hole });
} }
} }
} else {
var _currentTime = media.currentTime;
if (targetSeekPosition && _currentTime !== targetSeekPosition) {
if (bufferInfo.len === 0) {
var nextStart = bufferInfo.nextStart;
if (nextStart !== undefined && nextStart - targetSeekPosition < this.config.maxSeekHole) {
targetSeekPosition = nextStart;
_logger.logger.log('target seek position not buffered, seek to next buffered ' + targetSeekPosition);
}
}
_logger.logger.log('adjust currentTime from ' + _currentTime + ' to ' + targetSeekPosition);
media.currentTime = targetSeekPosition;
}
} }
} }
} }
@ -5918,7 +5903,7 @@ var Hls = function () {
_createClass(Hls, null, [{ _createClass(Hls, null, [{
key: 'isSupported', key: 'isSupported',
value: function isSupported() { value: function isSupported() {
return window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"'); return window.MediaSource && typeof window.MediaSource.isTypeSupported === 'function' && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');
} }
}, { }, {
key: 'Events', key: 'Events',
@ -8841,8 +8826,9 @@ var XhrLoader = function () {
xhr.setRequestHeader('Range', 'bytes=' + this.byteRange); xhr.setRequestHeader('Range', 'bytes=' + this.byteRange);
} }
xhr.responseType = this.responseType; xhr.responseType = this.responseType;
this.stats.tfirst = null; var stats = this.stats;
this.stats.loaded = 0; stats.tfirst = 0;
stats.loaded = 0;
if (this.xhrSetup) { if (this.xhrSetup) {
this.xhrSetup(xhr, this.url); this.xhrSetup(xhr, this.url);
} }
@ -8860,7 +8846,7 @@ var XhrLoader = function () {
// http status between 200 to 299 are all successful // http status between 200 to 299 are all successful
if (status >= 200 && status < 300) { if (status >= 200 && status < 300) {
window.clearTimeout(this.timeoutHandle); window.clearTimeout(this.timeoutHandle);
stats.tload = performance.now(); stats.tload = Math.max(stats.tfirst, performance.now());
this.onSuccess(event, stats); this.onSuccess(event, stats);
} else { } else {
// error ... // error ...
@ -8889,8 +8875,8 @@ var XhrLoader = function () {
key: 'loadprogress', key: 'loadprogress',
value: function loadprogress(event) { value: function loadprogress(event) {
var stats = this.stats; var stats = this.stats;
if (stats.tfirst === null) { if (stats.tfirst === 0) {
stats.tfirst = performance.now(); stats.tfirst = Math.max(performance.now(), stats.trequest);
} }
stats.loaded = event.loaded; stats.loaded = event.loaded;
if (this.onProgress) { if (this.onProgress) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,6 @@
{ {
"name": "hls.js", "name": "hls.js",
"version": "0.5.36", "version": "0.5.39",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "Media Source Extension - HLS library, by/for Dailymotion", "description": "Media Source Extension - HLS library, by/for Dailymotion",
"homepage": "https://github.com/dailymotion/hls.js", "homepage": "https://github.com/dailymotion/hls.js",

View file

@ -34,7 +34,9 @@ class AbrController extends EventHandler {
if (!this.timer) { if (!this.timer) {
this.timer = setInterval(this.onCheck, 100); this.timer = setInterval(this.onCheck, 100);
} }
this.fragCurrent = data.frag; let frag = data.frag;
frag.trequest = performance.now();
this.fragCurrent = frag;
} }
abandonRulesCheck() { abandonRulesCheck() {
@ -57,12 +59,13 @@ class AbrController extends EventHandler {
let requestDelay = performance.now() - frag.trequest; let requestDelay = performance.now() - frag.trequest;
// monitor fragment load progress after half of expected fragment duration,to stabilize bitrate // monitor fragment load progress after half of expected fragment duration,to stabilize bitrate
if (requestDelay > (500 * frag.duration)) { if (requestDelay > (500 * frag.duration)) {
let loadRate = Math.max(1,frag.loaded * 1000 / requestDelay); // byte/s; at least 1 byte/s to avoid division by zero let levels = hls.levels,
if (frag.expectedLen < frag.loaded) { loadRate = Math.max(1,frag.loaded * 1000 / requestDelay), // byte/s; at least 1 byte/s to avoid division by zero
frag.expectedLen = frag.loaded; // compute expected fragment length using frag duration and level bitrate. also ensure that expected len is gte than already loaded size
} expectedLen = Math.max(frag.loaded, Math.round(frag.duration * levels[frag.level].bitrate / 8));
let pos = v.currentTime; let pos = v.currentTime;
let fragLoadedDelay = (frag.expectedLen - frag.loaded) / loadRate; let fragLoadedDelay = (expectedLen - frag.loaded) / loadRate;
let bufferStarvationDelay = BufferHelper.bufferInfo(v,pos,hls.config.maxBufferHole).end - pos; let bufferStarvationDelay = BufferHelper.bufferInfo(v,pos,hls.config.maxBufferHole).end - pos;
// consider emergency switch down only if we have less than 2 frag buffered AND // consider emergency switch down only if we have less than 2 frag buffered AND
// time to finish loading current fragment is bigger than buffer starvation delay // time to finish loading current fragment is bigger than buffer starvation delay
@ -75,7 +78,7 @@ class AbrController extends EventHandler {
// compute time to load next fragment at lower level // compute time to load next fragment at lower level
// 0.8 : consider only 80% of current bw to be conservative // 0.8 : consider only 80% of current bw to be conservative
// 8 = bits per byte (bps/Bps) // 8 = bits per byte (bps/Bps)
fragLevelNextLoadedDelay = frag.duration * hls.levels[nextLoadLevel].bitrate / (8 * 0.8 * loadRate); fragLevelNextLoadedDelay = frag.duration * levels[nextLoadLevel].bitrate / (8 * 0.8 * loadRate);
logger.log(`fragLoadedDelay/bufferStarvationDelay/fragLevelNextLoadedDelay[${nextLoadLevel}] :${fragLoadedDelay.toFixed(1)}/${bufferStarvationDelay.toFixed(1)}/${fragLevelNextLoadedDelay.toFixed(1)}`); logger.log(`fragLoadedDelay/bufferStarvationDelay/fragLevelNextLoadedDelay[${nextLoadLevel}] :${fragLoadedDelay.toFixed(1)}/${bufferStarvationDelay.toFixed(1)}/${fragLevelNextLoadedDelay.toFixed(1)}`);
if (fragLevelNextLoadedDelay < bufferStarvationDelay) { if (fragLevelNextLoadedDelay < bufferStarvationDelay) {
// we found a lower level that be rebuffering free with current estimated bw ! // we found a lower level that be rebuffering free with current estimated bw !

View file

@ -38,7 +38,7 @@ class EwmaBandWidthEstimator {
getEstimate() { getEstimate() {
if (this.fast_.getTotalWeight() < this.minWeight_) { if (!this.fast_ || this.fast_.getTotalWeight() < this.minWeight_) {
return this.defaultEstimate_; return this.defaultEstimate_;
} }
//console.log('slow estimate:'+ Math.round(this.slow_.getEstimate())); //console.log('slow estimate:'+ Math.round(this.slow_.getEstimate()));

View file

@ -199,9 +199,12 @@ class StreamController extends EventHandler {
if (bufferEnd < Math.max(start, end - maxLatency)) { if (bufferEnd < Math.max(start, end - maxLatency)) {
let targetLatency = config.liveSyncDuration !== undefined ? config.liveSyncDuration : config.liveSyncDurationCount * levelDetails.targetduration; let targetLatency = config.liveSyncDuration !== undefined ? config.liveSyncDuration : config.liveSyncDurationCount * levelDetails.targetduration;
this.seekAfterBuffered = start + Math.max(0, levelDetails.totalduration - targetLatency); let liveSyncPosition = start + Math.max(0, levelDetails.totalduration - targetLatency);
logger.log(`buffer end: ${bufferEnd} is located too far from the end of live sliding playlist, media position will be reseted to: ${this.seekAfterBuffered.toFixed(3)}`); logger.log(`buffer end: ${bufferEnd} is located too far from the end of live sliding playlist, reset currentTime to : ${liveSyncPosition.toFixed(3)}`);
bufferEnd = this.seekAfterBuffered; bufferEnd = liveSyncPosition;
if (media && media.readyState && media.duration > liveSyncPosition) {
media.currentTime = liveSyncPosition;
}
} }
// if end of buffer greater than live edge, don't load any fragment // if end of buffer greater than live edge, don't load any fragment
@ -306,11 +309,6 @@ class StreamController extends EventHandler {
hls.trigger(Event.KEY_LOADING, {frag: frag}); hls.trigger(Event.KEY_LOADING, {frag: frag});
} else { } else {
logger.log(`Loading ${frag.sn} of [${levelDetails.startSN} ,${levelDetails.endSN}],level ${level}, currentTime:${pos},bufferEnd:${bufferEnd.toFixed(3)}`); logger.log(`Loading ${frag.sn} of [${levelDetails.startSN} ,${levelDetails.endSN}],level ${level}, currentTime:${pos},bufferEnd:${bufferEnd.toFixed(3)}`);
frag.autoLevel = hls.autoLevelEnabled;
if (this.levels.length > 1) {
frag.expectedLen = Math.round(frag.duration * this.levels[level].bitrate / 8);
frag.trequest = performance.now();
}
// ensure that we are not reloading the same fragments in loop ... // ensure that we are not reloading the same fragments in loop ...
if (this.fragLoadIdx !== undefined) { if (this.fragLoadIdx !== undefined) {
this.fragLoadIdx++; this.fragLoadIdx++;
@ -331,6 +329,7 @@ class StreamController extends EventHandler {
frag.loadIdx = this.fragLoadIdx; frag.loadIdx = this.fragLoadIdx;
this.fragCurrent = frag; this.fragCurrent = frag;
this.startFragRequested = true; this.startFragRequested = true;
frag.autoLevel = hls.autoLevelEnabled;
hls.trigger(Event.FRAG_LOADING, {frag: frag}); hls.trigger(Event.FRAG_LOADING, {frag: frag});
this.state = State.FRAG_LOADING; this.state = State.FRAG_LOADING;
} }
@ -988,37 +987,33 @@ class StreamController extends EventHandler {
_checkBuffer() { _checkBuffer() {
var media = this.media; var media = this.media;
if(media) { // if ready state different from HAVE_NOTHING (numeric value 0), we are allowed to seek
// compare readyState if(media && media.readyState) {
var readyState = media.readyState; let currentTime = media.currentTime,
// if ready state different from HAVE_NOTHING (numeric value 0), we are allowed to seek buffered = media.buffered;
if(readyState) { // adjust currentTime to start position on loaded metadata
var targetSeekPosition, currentTime; if(!this.loadedmetadata && buffered.length) {
// if seek after buffered defined, let's seek if within acceptable range this.loadedmetadata = true;
var seekAfterBuffered = this.seekAfterBuffered; // only adjust currentTime if startPosition not equal to 0
if(seekAfterBuffered) { let startPosition = this.startPosition;
if(media.duration >= seekAfterBuffered) { // if currentTime === 0 AND not matching with expected startPosition
targetSeekPosition = seekAfterBuffered; if (!currentTime && currentTime !== startPosition) {
this.seekAfterBuffered = undefined; if (startPosition) {
} logger.log(`target start position:${startPosition}`);
} else { // at that stage, there should be only one buffered range, as we reach that code after first fragment has been
currentTime = media.currentTime; let bufferStart = buffered.start(0),
var loadedmetadata = this.loadedmetadata; bufferEnd = buffered.end(0);
// if startPosition not buffered, let's seek to buffered.start(0)
// adjust currentTime to start position on loaded metadata if(startPosition < bufferStart || startPosition > bufferEnd) {
if(!loadedmetadata && media.buffered.length) { startPosition = bufferStart;
this.loadedmetadata = true; logger.log(`target start position not buffered, seek to buffered.start(0) ${bufferStart}`);
// only adjust currentTime if not equal to 0
if (!currentTime && currentTime !== this.startPosition) {
targetSeekPosition = this.startPosition;
} }
logger.log(`adjust currentTime from ${currentTime} to ${startPosition}`);
media.currentTime = startPosition;
} }
} }
if (targetSeekPosition) { } else {
currentTime = targetSeekPosition; let bufferInfo = BufferHelper.bufferInfo(media,currentTime,0),
logger.log(`target seek position:${targetSeekPosition}`);
}
var bufferInfo = BufferHelper.bufferInfo(media,currentTime,0),
expectedPlaying = !(media.paused || // not playing when media is paused expectedPlaying = !(media.paused || // not playing when media is paused
media.ended || // not playing when media is ended media.ended || // not playing when media is ended
media.buffered.length === 0), // not playing if nothing buffered media.buffered.length === 0), // not playing if nothing buffered
@ -1030,8 +1025,7 @@ _checkBuffer() {
logger.log(`playback not stuck anymore @${currentTime}`); logger.log(`playback not stuck anymore @${currentTime}`);
} }
// check buffer upfront // check buffer upfront
// if less than jumpThreshold second is buffered, and media is expected to play but playhead is not moving, // if less than jumpThreshold second is buffered, let's check in more details
// and we have a new buffer range available upfront, let's seek to that one
if(expectedPlaying && bufferInfo.len <= jumpThreshold) { if(expectedPlaying && bufferInfo.len <= jumpThreshold) {
if(playheadMoving) { if(playheadMoving) {
// playhead moving // playhead moving
@ -1048,7 +1042,7 @@ _checkBuffer() {
this.seekHoleNudgeDuration += this.config.seekHoleNudgeDuration; this.seekHoleNudgeDuration += this.config.seekHoleNudgeDuration;
} }
} }
// if we are below threshold, try to jump if next buffer range is close // if we are below threshold, try to jump to start of next buffer range if close
if(bufferInfo.len <= jumpThreshold) { if(bufferInfo.len <= jumpThreshold) {
// no buffer available @ currentTime, check if next buffer is close (within a config.maxSeekHole second range) // no buffer available @ currentTime, check if next buffer is close (within a config.maxSeekHole second range)
var nextBufferStart = bufferInfo.nextStart, delta = nextBufferStart-currentTime; var nextBufferStart = bufferInfo.nextStart, delta = nextBufferStart-currentTime;
@ -1063,20 +1057,6 @@ _checkBuffer() {
this.hls.trigger(Event.ERROR, {type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_SEEK_OVER_HOLE, fatal: false, hole : hole}); this.hls.trigger(Event.ERROR, {type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_SEEK_OVER_HOLE, fatal: false, hole : hole});
} }
} }
} else {
let currentTime = media.currentTime;
if (targetSeekPosition && currentTime !== targetSeekPosition) {
if(bufferInfo.len === 0) {
let nextStart = bufferInfo.nextStart;
if (nextStart !== undefined &&
(nextStart - targetSeekPosition) < this.config.maxSeekHole) {
targetSeekPosition = nextStart;
logger.log(`target seek position not buffered, seek to next buffered ${targetSeekPosition}`);
}
}
logger.log(`adjust currentTime from ${currentTime} to ${targetSeekPosition}`);
media.currentTime = targetSeekPosition;
}
} }
} }
} }

View file

@ -22,7 +22,9 @@ import KeyLoader from './loader/key-loader';
class Hls { class Hls {
static isSupported() { static isSupported() {
return (window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')); return (window.MediaSource &&
typeof window.MediaSource.isTypeSupported === 'function' &&
window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"'));
} }
static get Events() { static get Events() {

View file

@ -63,8 +63,9 @@ class XhrLoader {
xhr.setRequestHeader('Range', 'bytes=' + this.byteRange); xhr.setRequestHeader('Range', 'bytes=' + this.byteRange);
} }
xhr.responseType = this.responseType; xhr.responseType = this.responseType;
this.stats.tfirst = null; let stats = this.stats;
this.stats.loaded = 0; stats.tfirst = 0;
stats.loaded = 0;
if (this.xhrSetup) { if (this.xhrSetup) {
this.xhrSetup(xhr, this.url); this.xhrSetup(xhr, this.url);
} }
@ -81,7 +82,7 @@ class XhrLoader {
// http status between 200 to 299 are all successful // http status between 200 to 299 are all successful
if (status >= 200 && status < 300) { if (status >= 200 && status < 300) {
window.clearTimeout(this.timeoutHandle); window.clearTimeout(this.timeoutHandle);
stats.tload = performance.now(); stats.tload = Math.max(stats.tfirst,performance.now());
this.onSuccess(event, stats); this.onSuccess(event, stats);
} else { } else {
// error ... // error ...
@ -108,8 +109,8 @@ class XhrLoader {
loadprogress(event) { loadprogress(event) {
var stats = this.stats; var stats = this.stats;
if (stats.tfirst === null) { if (stats.tfirst === 0) {
stats.tfirst = performance.now(); stats.tfirst = Math.max(performance.now(), stats.trequest);
} }
stats.loaded = event.loaded; stats.loaded = event.loaded;
if (this.onProgress) { if (this.onProgress) {

View file

@ -32,14 +32,14 @@
"web-component-tester": "^4.0.0", "web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"homepage": "https://github.com/polymerelements/iron-icon", "homepage": "https://github.com/PolymerElements/iron-icon",
"_release": "1.0.8", "_release": "1.0.8",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.8", "tag": "v1.0.8",
"commit": "f36b38928849ef3853db727faa8c9ef104d611eb" "commit": "f36b38928849ef3853db727faa8c9ef104d611eb"
}, },
"_source": "git://github.com/polymerelements/iron-icon.git", "_source": "git://github.com/PolymerElements/iron-icon.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymerelements/iron-icon" "_originalSource": "PolymerElements/iron-icon"
} }

View file

@ -36,7 +36,7 @@
"tag": "v1.5.2", "tag": "v1.5.2",
"commit": "18e8e12dcd9a4560de480562f65935feed334b86" "commit": "18e8e12dcd9a4560de480562f65935feed334b86"
}, },
"_source": "git://github.com/PolymerElements/iron-selector.git", "_source": "git://github.com/polymerelements/iron-selector.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "PolymerElements/iron-selector" "_originalSource": "polymerelements/iron-selector"
} }

View file

@ -39,6 +39,6 @@
"commit": "ce5b9fb2d8aa03c698410e2e55cffcfa0b788a3a" "commit": "ce5b9fb2d8aa03c698410e2e55cffcfa0b788a3a"
}, },
"_source": "git://github.com/Polymer/polymer.git", "_source": "git://github.com/Polymer/polymer.git",
"_target": "^1.1.0", "_target": "^1.0.0",
"_originalSource": "Polymer/polymer" "_originalSource": "Polymer/polymer"
} }