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

@ -34,7 +34,9 @@ class AbrController extends EventHandler {
if (!this.timer) {
this.timer = setInterval(this.onCheck, 100);
}
this.fragCurrent = data.frag;
let frag = data.frag;
frag.trequest = performance.now();
this.fragCurrent = frag;
}
abandonRulesCheck() {
@ -57,12 +59,13 @@ class AbrController extends EventHandler {
let requestDelay = performance.now() - frag.trequest;
// monitor fragment load progress after half of expected fragment duration,to stabilize bitrate
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
if (frag.expectedLen < frag.loaded) {
frag.expectedLen = frag.loaded;
}
let levels = hls.levels,
loadRate = Math.max(1,frag.loaded * 1000 / requestDelay), // 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));
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;
// 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
@ -75,7 +78,7 @@ class AbrController extends EventHandler {
// compute time to load next fragment at lower level
// 0.8 : consider only 80% of current bw to be conservative
// 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)}`);
if (fragLevelNextLoadedDelay < bufferStarvationDelay) {
// we found a lower level that be rebuffering free with current estimated bw !

View file

@ -38,7 +38,7 @@ class EwmaBandWidthEstimator {
getEstimate() {
if (this.fast_.getTotalWeight() < this.minWeight_) {
if (!this.fast_ || this.fast_.getTotalWeight() < this.minWeight_) {
return this.defaultEstimate_;
}
//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)) {
let targetLatency = config.liveSyncDuration !== undefined ? config.liveSyncDuration : config.liveSyncDurationCount * levelDetails.targetduration;
this.seekAfterBuffered = 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)}`);
bufferEnd = this.seekAfterBuffered;
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, reset currentTime to : ${liveSyncPosition.toFixed(3)}`);
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
@ -306,11 +309,6 @@ class StreamController extends EventHandler {
hls.trigger(Event.KEY_LOADING, {frag: frag});
} else {
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 ...
if (this.fragLoadIdx !== undefined) {
this.fragLoadIdx++;
@ -331,6 +329,7 @@ class StreamController extends EventHandler {
frag.loadIdx = this.fragLoadIdx;
this.fragCurrent = frag;
this.startFragRequested = true;
frag.autoLevel = hls.autoLevelEnabled;
hls.trigger(Event.FRAG_LOADING, {frag: frag});
this.state = State.FRAG_LOADING;
}
@ -988,37 +987,33 @@ class StreamController extends EventHandler {
_checkBuffer() {
var media = this.media;
if(media) {
// compare readyState
var readyState = media.readyState;
// if ready state different from HAVE_NOTHING (numeric value 0), we are allowed to seek
if(readyState) {
var targetSeekPosition, currentTime;
// if seek after buffered defined, let's seek if within acceptable range
var seekAfterBuffered = this.seekAfterBuffered;
if(seekAfterBuffered) {
if(media.duration >= seekAfterBuffered) {
targetSeekPosition = seekAfterBuffered;
this.seekAfterBuffered = undefined;
}
} else {
currentTime = media.currentTime;
var loadedmetadata = this.loadedmetadata;
// adjust currentTime to start position on loaded metadata
if(!loadedmetadata && media.buffered.length) {
this.loadedmetadata = true;
// only adjust currentTime if not equal to 0
if (!currentTime && currentTime !== this.startPosition) {
targetSeekPosition = this.startPosition;
// if ready state different from HAVE_NOTHING (numeric value 0), we are allowed to seek
if(media && media.readyState) {
let currentTime = media.currentTime,
buffered = media.buffered;
// adjust currentTime to start position on loaded metadata
if(!this.loadedmetadata && buffered.length) {
this.loadedmetadata = true;
// only adjust currentTime if startPosition not equal to 0
let startPosition = this.startPosition;
// if currentTime === 0 AND not matching with expected startPosition
if (!currentTime && currentTime !== startPosition) {
if (startPosition) {
logger.log(`target start position:${startPosition}`);
// at that stage, there should be only one buffered range, as we reach that code after first fragment has been
let bufferStart = buffered.start(0),
bufferEnd = buffered.end(0);
// if startPosition not buffered, let's seek to buffered.start(0)
if(startPosition < bufferStart || startPosition > bufferEnd) {
startPosition = bufferStart;
logger.log(`target start position not buffered, seek to buffered.start(0) ${bufferStart}`);
}
logger.log(`adjust currentTime from ${currentTime} to ${startPosition}`);
media.currentTime = startPosition;
}
}
if (targetSeekPosition) {
currentTime = targetSeekPosition;
logger.log(`target seek position:${targetSeekPosition}`);
}
var bufferInfo = BufferHelper.bufferInfo(media,currentTime,0),
} else {
let bufferInfo = BufferHelper.bufferInfo(media,currentTime,0),
expectedPlaying = !(media.paused || // not playing when media is paused
media.ended || // not playing when media is ended
media.buffered.length === 0), // not playing if nothing buffered
@ -1030,8 +1025,7 @@ _checkBuffer() {
logger.log(`playback not stuck anymore @${currentTime}`);
}
// check buffer upfront
// if less than jumpThreshold second is buffered, and media is expected to play but playhead is not moving,
// and we have a new buffer range available upfront, let's seek to that one
// if less than jumpThreshold second is buffered, let's check in more details
if(expectedPlaying && bufferInfo.len <= jumpThreshold) {
if(playheadMoving) {
// playhead moving
@ -1048,7 +1042,7 @@ _checkBuffer() {
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) {
// no buffer available @ currentTime, check if next buffer is close (within a config.maxSeekHole second range)
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});
}
}
} 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 {
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() {

View file

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