mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
update components
This commit is contained in:
parent
84945cabc4
commit
ab2d2eaf94
111 changed files with 4302 additions and 3100 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hls.js",
|
||||
"version": "0.5.35",
|
||||
"version": "0.5.36",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Media Source Extension - HLS library, by/for Dailymotion",
|
||||
"homepage": "https://github.com/dailymotion/hls.js",
|
||||
|
@ -16,11 +16,11 @@
|
|||
"test",
|
||||
"tests"
|
||||
],
|
||||
"_release": "0.5.35",
|
||||
"_release": "0.5.36",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v0.5.35",
|
||||
"commit": "ae83fd3b6f87c2b62dd4ca7419589cefbfafc394"
|
||||
"tag": "v0.5.36",
|
||||
"commit": "a39814dc1e5be2516518a30edf9f1629e05dea27"
|
||||
},
|
||||
"_source": "git://github.com/dailymotion/hls.js.git",
|
||||
"_target": "~0.5.7",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hls.js",
|
||||
"version": "0.5.35",
|
||||
"version": "0.5.36",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Media Source Extension - HLS library, by/for Dailymotion",
|
||||
"homepage": "https://github.com/dailymotion/hls.js",
|
||||
|
|
|
@ -535,7 +535,7 @@
|
|||
ctx.fillStyle = "black";
|
||||
ctx.font = "15px Arial";
|
||||
legend = event.type;
|
||||
if (event.name) legend+= ':' + event.name;
|
||||
if (event.name !== undefined) legend+= ':' + event.name;
|
||||
ctx.fillText(legend,5,yoffset+15);
|
||||
|
||||
|
||||
|
|
148
dashboard-ui/bower_components/hls.js/dist/hls.js
vendored
148
dashboard-ui/bower_components/hls.js/dist/hls.js
vendored
|
@ -646,10 +646,16 @@ var BufferController = function (_EventHandler) {
|
|||
function BufferController(hls) {
|
||||
_classCallCheck(this, BufferController);
|
||||
|
||||
// the value that we have set mediasource.duration to
|
||||
// (the actual duration may be tweaked slighly by the browser)
|
||||
|
||||
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(BufferController).call(this, hls, _events2.default.MEDIA_ATTACHING, _events2.default.MEDIA_DETACHING, _events2.default.BUFFER_RESET, _events2.default.BUFFER_APPENDING, _events2.default.BUFFER_CODECS, _events2.default.BUFFER_EOS, _events2.default.BUFFER_FLUSHING, _events2.default.LEVEL_UPDATED));
|
||||
|
||||
_this._msDuration = null;
|
||||
// the value that we want to set mediaSource.duration to
|
||||
_this._levelDuration = null;
|
||||
|
||||
// Source Buffer listeners
|
||||
|
||||
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(BufferController).call(this, hls, _events2.default.MEDIA_ATTACHING, _events2.default.MEDIA_DETACHING, _events2.default.BUFFER_RESET, _events2.default.BUFFER_APPENDING, _events2.default.BUFFER_CODECS, _events2.default.BUFFER_EOS, _events2.default.BUFFER_FLUSHING));
|
||||
|
||||
_this.onsbue = _this.onSBUpdateEnd.bind(_this);
|
||||
_this.onsbe = _this.onSBUpdateError.bind(_this);
|
||||
return _this;
|
||||
|
@ -852,6 +858,50 @@ var BufferController = function (_EventHandler) {
|
|||
this.flushBufferCounter = 0;
|
||||
this.doFlush();
|
||||
}
|
||||
}, {
|
||||
key: 'onLevelUpdated',
|
||||
value: function onLevelUpdated(event) {
|
||||
var details = event.details;
|
||||
if (details.fragments.length === 0) {
|
||||
return;
|
||||
}
|
||||
this._levelDuration = details.totalduration + details.fragments[0].start;
|
||||
this.updateMediaElementDuration();
|
||||
}
|
||||
|
||||
// https://github.com/dailymotion/hls.js/issues/355
|
||||
|
||||
}, {
|
||||
key: 'updateMediaElementDuration',
|
||||
value: function updateMediaElementDuration() {
|
||||
if (this._levelDuration === null) {
|
||||
return;
|
||||
}
|
||||
var media = this.media;
|
||||
var mediaSource = this.mediaSource;
|
||||
if (!media || !mediaSource || media.readyState === 0 || mediaSource.readyState !== 'open') {
|
||||
return;
|
||||
}
|
||||
for (var type in mediaSource.sourceBuffers) {
|
||||
if (mediaSource.sourceBuffers[type].updating) {
|
||||
// can't set duration whilst a buffer is updating
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this._msDuration === null) {
|
||||
// initialise to the value that the media source is reporting
|
||||
this._msDuration = mediaSource.duration;
|
||||
}
|
||||
// this._levelDuration was the last value we set.
|
||||
// not using mediaSource.duration as the browser may tweak this value
|
||||
// only update mediasource duration if its value increase, this is to avoid
|
||||
// flushing already buffered portion when switching between quality level, as they
|
||||
if (this._levelDuration > this._msDuration) {
|
||||
_logger.logger.log('Updating mediasource duration to ' + this._levelDuration);
|
||||
mediaSource.duration = this._levelDuration;
|
||||
this._msDuration = this._levelDuration;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'doFlush',
|
||||
value: function doFlush() {
|
||||
|
@ -1183,8 +1233,6 @@ var EwmaBandWidthEstimator = function () {
|
|||
this.defaultEstimate_ = 5e5; // 500kbps
|
||||
this.minWeight_ = 0.001;
|
||||
this.minDelayMs_ = 50;
|
||||
this.fast_ = new _ewma2.default(hls.config.abrEwmaFast);
|
||||
this.slow_ = new _ewma2.default(hls.config.abrEwmaSlow);
|
||||
}
|
||||
|
||||
_createClass(EwmaBandWidthEstimator, [{
|
||||
|
@ -1195,6 +1243,14 @@ var EwmaBandWidthEstimator = function () {
|
|||
//console.log('instant bw:'+ Math.round(bandwidth));
|
||||
// we weight sample using loading duration....
|
||||
var weigth = durationMs / 1000;
|
||||
|
||||
// lazy initialization. this allows to take into account config param changes that could happen after Hls instantiation,
|
||||
// but before first fragment loading. this is useful to A/B tests those params
|
||||
if (!this.fast_) {
|
||||
var config = this.hls.config;
|
||||
this.fast_ = new _ewma2.default(config.abrEwmaFast);
|
||||
this.slow_ = new _ewma2.default(config.abrEwmaSlow);
|
||||
}
|
||||
this.fast_.sample(weigth, bandwidth);
|
||||
this.slow_.sample(weigth, bandwidth);
|
||||
}
|
||||
|
@ -1726,13 +1782,13 @@ var StreamController = function (_EventHandler) {
|
|||
}, {
|
||||
key: 'doTick',
|
||||
value: function doTick() {
|
||||
var _this2 = this;
|
||||
|
||||
var pos,
|
||||
level,
|
||||
levelDetails,
|
||||
hls = this.hls,
|
||||
config = hls.config;
|
||||
config = hls.config,
|
||||
media = this.media,
|
||||
isSeeking = media && media.seeking;
|
||||
//logger.log(this.state);
|
||||
switch (this.state) {
|
||||
case State.ERROR:
|
||||
|
@ -1759,7 +1815,7 @@ var StreamController = function (_EventHandler) {
|
|||
// start fragment already requested OR start frag prefetch disable
|
||||
// exit loop
|
||||
// => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
|
||||
if (!this.media && (this.startFragRequested || !config.startFragPrefetch)) {
|
||||
if (!media && (this.startFragRequested || !config.startFragPrefetch)) {
|
||||
break;
|
||||
}
|
||||
// determine next candidate fragment to be loaded, based on current position and
|
||||
|
@ -1767,12 +1823,12 @@ var StreamController = function (_EventHandler) {
|
|||
// ensure 60s of buffer upfront
|
||||
// if we have not yet loaded any fragment, start loading from start position
|
||||
if (this.loadedmetadata) {
|
||||
pos = this.media.currentTime;
|
||||
pos = media.currentTime;
|
||||
} else {
|
||||
pos = this.nextLoadPosition;
|
||||
}
|
||||
level = hls.nextLoadLevel;
|
||||
var bufferInfo = _bufferHelper2.default.bufferInfo(this.media, pos, config.maxBufferHole),
|
||||
var bufferInfo = _bufferHelper2.default.bufferInfo(media, pos, config.maxBufferHole),
|
||||
bufferLen = bufferInfo.len,
|
||||
bufferEnd = bufferInfo.end,
|
||||
fragPrevious = this.fragPrevious,
|
||||
|
@ -1807,7 +1863,7 @@ var StreamController = function (_EventHandler) {
|
|||
// in case of live playlist we need to ensure that requested position is not located before playlist start
|
||||
if (levelDetails.live) {
|
||||
// check if requested position is within seekable boundaries :
|
||||
//logger.log(`start/pos/bufEnd/seeking:${start.toFixed(3)}/${pos.toFixed(3)}/${bufferEnd.toFixed(3)}/${this.media.seeking}`);
|
||||
//logger.log(`start/pos/bufEnd/seeking:${start.toFixed(3)}/${pos.toFixed(3)}/${bufferEnd.toFixed(3)}/${media.seeking}`);
|
||||
var maxLatency = config.liveMaxLatencyDuration !== undefined ? config.liveMaxLatencyDuration : config.liveMaxLatencyDurationCount * levelDetails.targetduration;
|
||||
|
||||
if (bufferEnd < Math.max(start, end - maxLatency)) {
|
||||
|
@ -1858,13 +1914,13 @@ var StreamController = function (_EventHandler) {
|
|||
}
|
||||
if (!frag) {
|
||||
(function () {
|
||||
var foundFrag = void 0;
|
||||
var maxFragLookUpTolerance = config.maxFragLookUpTolerance;
|
||||
if (bufferEnd < end) {
|
||||
if (bufferEnd > end - maxFragLookUpTolerance) {
|
||||
// no frag look up tolerance in case bufferEnd close to end, or media seeking
|
||||
if (bufferEnd > end - maxFragLookUpTolerance || isSeeking) {
|
||||
maxFragLookUpTolerance = 0;
|
||||
}
|
||||
foundFrag = _binarySearch2.default.search(fragments, function (candidate) {
|
||||
frag = _binarySearch2.default.search(fragments, function (candidate) {
|
||||
// offset should be within fragment boundary - config.maxFragLookUpTolerance
|
||||
// this is to cope with situations like
|
||||
// bufferEnd = 9.991
|
||||
|
@ -1887,35 +1943,32 @@ var StreamController = function (_EventHandler) {
|
|||
});
|
||||
} else {
|
||||
// reach end of playlist
|
||||
foundFrag = fragments[fragLen - 1];
|
||||
}
|
||||
if (foundFrag) {
|
||||
frag = foundFrag;
|
||||
start = foundFrag.start;
|
||||
//logger.log('find SN matching with pos:' + bufferEnd + ':' + frag.sn);
|
||||
if (fragPrevious && frag.level === fragPrevious.level && frag.sn === fragPrevious.sn) {
|
||||
if (frag.sn < levelDetails.endSN) {
|
||||
frag = fragments[frag.sn + 1 - levelDetails.startSN];
|
||||
_logger.logger.log('SN just loaded, load next one: ' + frag.sn);
|
||||
} else {
|
||||
// have we reached end of VOD playlist ?
|
||||
if (!levelDetails.live) {
|
||||
// Finalize the media stream
|
||||
_this2.hls.trigger(_events2.default.BUFFER_EOS);
|
||||
// We might be loading the last fragment but actually the media
|
||||
// is currently processing a seek command and waiting for new data to resume at another point.
|
||||
// Going to ended state while media is seeking can spawn an infinite buffering broken state.
|
||||
if (!_this2.media.seeking) {
|
||||
_this2.state = State.ENDED;
|
||||
}
|
||||
}
|
||||
frag = null;
|
||||
}
|
||||
}
|
||||
frag = fragments[fragLen - 1];
|
||||
}
|
||||
})();
|
||||
}
|
||||
if (frag) {
|
||||
start = frag.start;
|
||||
//logger.log('find SN matching with pos:' + bufferEnd + ':' + frag.sn);
|
||||
if (fragPrevious && frag.level === fragPrevious.level && frag.sn === fragPrevious.sn) {
|
||||
if (frag.sn < levelDetails.endSN) {
|
||||
frag = fragments[frag.sn + 1 - levelDetails.startSN];
|
||||
_logger.logger.log('SN just loaded, load next one: ' + frag.sn);
|
||||
} else {
|
||||
// have we reached end of VOD playlist ?
|
||||
if (!levelDetails.live) {
|
||||
// Finalize the media stream
|
||||
this.hls.trigger(_events2.default.BUFFER_EOS);
|
||||
// We might be loading the last fragment but actually the media
|
||||
// is currently processing a seek command and waiting for new data to resume at another point.
|
||||
// Going to ended state while media is seeking can spawn an infinite buffering broken state.
|
||||
if (!isSeeking) {
|
||||
this.state = State.ENDED;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
//logger.log(' loading frag ' + i +',pos/bufEnd:' + pos.toFixed(3) + '/' + bufferEnd.toFixed(3));
|
||||
if (frag.decryptdata.uri != null && frag.decryptdata.key == null) {
|
||||
_logger.logger.log('Loading key for ' + frag.sn + ' of [' + levelDetails.startSN + ' ,' + levelDetails.endSN + '],level ' + level);
|
||||
|
@ -1964,8 +2017,6 @@ var StreamController = function (_EventHandler) {
|
|||
case State.FRAG_LOADING_WAITING_RETRY:
|
||||
var now = performance.now();
|
||||
var retryDate = this.retryDate;
|
||||
var media = this.media;
|
||||
var isSeeking = media && media.seeking;
|
||||
// if current time is gt than retryDate, or if media seeking let's switch to IDLE state to retry loading
|
||||
if (!retryDate || now >= retryDate || isSeeking) {
|
||||
_logger.logger.log('mediaController: retryDate reached, switch back to IDLE state');
|
||||
|
@ -2486,7 +2537,7 @@ var StreamController = function (_EventHandler) {
|
|||
}, {
|
||||
key: 'onFragParsingData',
|
||||
value: function onFragParsingData(data) {
|
||||
var _this3 = this;
|
||||
var _this2 = this;
|
||||
|
||||
if (this.state === State.PARSING) {
|
||||
this.tparse2 = Date.now();
|
||||
|
@ -2501,7 +2552,7 @@ var StreamController = function (_EventHandler) {
|
|||
|
||||
[data.data1, data.data2].forEach(function (buffer) {
|
||||
if (buffer) {
|
||||
_this3.pendingAppending++;
|
||||
_this2.pendingAppending++;
|
||||
hls.trigger(_events2.default.BUFFER_APPENDING, { type: data.type, data: buffer });
|
||||
}
|
||||
});
|
||||
|
@ -2645,8 +2696,11 @@ var StreamController = function (_EventHandler) {
|
|||
_logger.logger.log('target seek position:' + targetSeekPosition);
|
||||
}
|
||||
var bufferInfo = _bufferHelper2.default.bufferInfo(media, currentTime, 0),
|
||||
expectedPlaying = !(media.paused || media.ended || media.seeking || media.buffered.length === 0),
|
||||
jumpThreshold = 0.4,
|
||||
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
|
||||
jumpThreshold = 0.4,
|
||||
// tolerance needed as some browsers stalls playback before reaching buffered range end
|
||||
playheadMoving = currentTime > media.playbackRate * this.lastCurrentTime;
|
||||
|
||||
|
@ -2678,7 +2732,7 @@ var StreamController = function (_EventHandler) {
|
|||
// no buffer available @ currentTime, check if next buffer is close (within a config.maxSeekHole second range)
|
||||
var nextBufferStart = bufferInfo.nextStart,
|
||||
delta = nextBufferStart - currentTime;
|
||||
if (nextBufferStart && delta < this.config.maxSeekHole && delta > 0 && !media.seeking) {
|
||||
if (nextBufferStart && delta < this.config.maxSeekHole && delta > 0) {
|
||||
// next buffer is close ! adjust currentTime to nextBufferStart
|
||||
// this will ensure effective video decoding
|
||||
_logger.logger.log('adjust currentTime from ' + media.currentTime + ' to next buffered @ ' + nextBufferStart + ' + nudge ' + this.seekHoleNudgeDuration);
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "hls.js",
|
||||
"version": "0.5.35",
|
||||
"version": "0.5.36",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Media Source Extension - HLS library, by/for Dailymotion",
|
||||
"homepage": "https://github.com/dailymotion/hls.js",
|
||||
|
|
|
@ -18,7 +18,14 @@ class BufferController extends EventHandler {
|
|||
Event.BUFFER_APPENDING,
|
||||
Event.BUFFER_CODECS,
|
||||
Event.BUFFER_EOS,
|
||||
Event.BUFFER_FLUSHING);
|
||||
Event.BUFFER_FLUSHING,
|
||||
Event.LEVEL_UPDATED);
|
||||
|
||||
// the value that we have set mediasource.duration to
|
||||
// (the actual duration may be tweaked slighly by the browser)
|
||||
this._msDuration = null;
|
||||
// the value that we want to set mediaSource.duration to
|
||||
this._levelDuration = null;
|
||||
|
||||
// Source Buffer listeners
|
||||
this.onsbue = this.onSBUpdateEnd.bind(this);
|
||||
|
@ -209,6 +216,46 @@ class BufferController extends EventHandler {
|
|||
this.doFlush();
|
||||
}
|
||||
|
||||
onLevelUpdated(event) {
|
||||
let details = event.details;
|
||||
if (details.fragments.length === 0) {
|
||||
return;
|
||||
}
|
||||
this._levelDuration = details.totalduration + details.fragments[0].start;
|
||||
this.updateMediaElementDuration();
|
||||
}
|
||||
|
||||
// https://github.com/dailymotion/hls.js/issues/355
|
||||
updateMediaElementDuration() {
|
||||
if (this._levelDuration === null) {
|
||||
return;
|
||||
}
|
||||
let media = this.media;
|
||||
let mediaSource = this.mediaSource;
|
||||
if (!media || !mediaSource || media.readyState === 0 || mediaSource.readyState !== 'open') {
|
||||
return;
|
||||
}
|
||||
for (let type in mediaSource.sourceBuffers) {
|
||||
if (mediaSource.sourceBuffers[type].updating) {
|
||||
// can't set duration whilst a buffer is updating
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this._msDuration === null) {
|
||||
// initialise to the value that the media source is reporting
|
||||
this._msDuration = mediaSource.duration;
|
||||
}
|
||||
// this._levelDuration was the last value we set.
|
||||
// not using mediaSource.duration as the browser may tweak this value
|
||||
// only update mediasource duration if its value increase, this is to avoid
|
||||
// flushing already buffered portion when switching between quality level, as they
|
||||
if (this._levelDuration > this._msDuration) {
|
||||
logger.log(`Updating mediasource duration to ${this._levelDuration}`);
|
||||
mediaSource.duration = this._levelDuration;
|
||||
this._msDuration = this._levelDuration;
|
||||
}
|
||||
}
|
||||
|
||||
doFlush() {
|
||||
// loop through all buffer ranges to flush
|
||||
while(this.flushRange.length) {
|
||||
|
|
|
@ -16,8 +16,6 @@ class EwmaBandWidthEstimator {
|
|||
this.defaultEstimate_ = 5e5; // 500kbps
|
||||
this.minWeight_ = 0.001;
|
||||
this.minDelayMs_ = 50;
|
||||
this.fast_ = new EWMA(hls.config.abrEwmaFast);
|
||||
this.slow_ = new EWMA(hls.config.abrEwmaSlow);
|
||||
}
|
||||
|
||||
sample(durationMs,numBytes) {
|
||||
|
@ -26,6 +24,14 @@ class EwmaBandWidthEstimator {
|
|||
//console.log('instant bw:'+ Math.round(bandwidth));
|
||||
// we weight sample using loading duration....
|
||||
var weigth = durationMs / 1000;
|
||||
|
||||
// lazy initialization. this allows to take into account config param changes that could happen after Hls instantiation,
|
||||
// but before first fragment loading. this is useful to A/B tests those params
|
||||
if(!this.fast_) {
|
||||
let config = this.hls.config;
|
||||
this.fast_ = new EWMA(config.abrEwmaFast);
|
||||
this.slow_ = new EWMA(config.abrEwmaSlow);
|
||||
}
|
||||
this.fast_.sample(weigth,bandwidth);
|
||||
this.slow_.sample(weigth,bandwidth);
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ class StreamController extends EventHandler {
|
|||
}
|
||||
|
||||
doTick() {
|
||||
var pos, level, levelDetails, hls = this.hls, config = hls.config;
|
||||
var pos, level, levelDetails, hls = this.hls, config = hls.config, media = this.media, isSeeking = media && media.seeking;
|
||||
//logger.log(this.state);
|
||||
switch(this.state) {
|
||||
case State.ERROR:
|
||||
|
@ -145,7 +145,7 @@ class StreamController extends EventHandler {
|
|||
// start fragment already requested OR start frag prefetch disable
|
||||
// exit loop
|
||||
// => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
|
||||
if (!this.media &&
|
||||
if (!media &&
|
||||
(this.startFragRequested || !config.startFragPrefetch)) {
|
||||
break;
|
||||
}
|
||||
|
@ -154,12 +154,12 @@ class StreamController extends EventHandler {
|
|||
// ensure 60s of buffer upfront
|
||||
// if we have not yet loaded any fragment, start loading from start position
|
||||
if (this.loadedmetadata) {
|
||||
pos = this.media.currentTime;
|
||||
pos = media.currentTime;
|
||||
} else {
|
||||
pos = this.nextLoadPosition;
|
||||
}
|
||||
level = hls.nextLoadLevel;
|
||||
var bufferInfo = BufferHelper.bufferInfo(this.media,pos,config.maxBufferHole),
|
||||
var bufferInfo = BufferHelper.bufferInfo(media,pos,config.maxBufferHole),
|
||||
bufferLen = bufferInfo.len,
|
||||
bufferEnd = bufferInfo.end,
|
||||
fragPrevious = this.fragPrevious,
|
||||
|
@ -194,7 +194,7 @@ class StreamController extends EventHandler {
|
|||
// in case of live playlist we need to ensure that requested position is not located before playlist start
|
||||
if (levelDetails.live) {
|
||||
// check if requested position is within seekable boundaries :
|
||||
//logger.log(`start/pos/bufEnd/seeking:${start.toFixed(3)}/${pos.toFixed(3)}/${bufferEnd.toFixed(3)}/${this.media.seeking}`);
|
||||
//logger.log(`start/pos/bufEnd/seeking:${start.toFixed(3)}/${pos.toFixed(3)}/${bufferEnd.toFixed(3)}/${media.seeking}`);
|
||||
let maxLatency = config.liveMaxLatencyDuration !== undefined ? config.liveMaxLatencyDuration : config.liveMaxLatencyDurationCount*levelDetails.targetduration;
|
||||
|
||||
if (bufferEnd < Math.max(start, end - maxLatency)) {
|
||||
|
@ -244,13 +244,13 @@ class StreamController extends EventHandler {
|
|||
}
|
||||
}
|
||||
if (!frag) {
|
||||
let foundFrag;
|
||||
let maxFragLookUpTolerance = config.maxFragLookUpTolerance;
|
||||
if (bufferEnd < end) {
|
||||
if (bufferEnd > end - maxFragLookUpTolerance) {
|
||||
// no frag look up tolerance in case bufferEnd close to end, or media seeking
|
||||
if (bufferEnd > end - maxFragLookUpTolerance || isSeeking) {
|
||||
maxFragLookUpTolerance = 0;
|
||||
}
|
||||
foundFrag = BinarySearch.search(fragments, (candidate) => {
|
||||
frag = BinarySearch.search(fragments, (candidate) => {
|
||||
// offset should be within fragment boundary - config.maxFragLookUpTolerance
|
||||
// this is to cope with situations like
|
||||
// bufferEnd = 9.991
|
||||
|
@ -274,34 +274,31 @@ class StreamController extends EventHandler {
|
|||
});
|
||||
} else {
|
||||
// reach end of playlist
|
||||
foundFrag = fragments[fragLen-1];
|
||||
}
|
||||
if (foundFrag) {
|
||||
frag = foundFrag;
|
||||
start = foundFrag.start;
|
||||
//logger.log('find SN matching with pos:' + bufferEnd + ':' + frag.sn);
|
||||
if (fragPrevious && frag.level === fragPrevious.level && frag.sn === fragPrevious.sn) {
|
||||
if (frag.sn < levelDetails.endSN) {
|
||||
frag = fragments[frag.sn + 1 - levelDetails.startSN];
|
||||
logger.log(`SN just loaded, load next one: ${frag.sn}`);
|
||||
} else {
|
||||
// have we reached end of VOD playlist ?
|
||||
if (!levelDetails.live) {
|
||||
// Finalize the media stream
|
||||
this.hls.trigger(Event.BUFFER_EOS);
|
||||
// We might be loading the last fragment but actually the media
|
||||
// is currently processing a seek command and waiting for new data to resume at another point.
|
||||
// Going to ended state while media is seeking can spawn an infinite buffering broken state.
|
||||
if (!this.media.seeking) {
|
||||
this.state = State.ENDED;
|
||||
}
|
||||
}
|
||||
frag = null;
|
||||
}
|
||||
}
|
||||
frag = fragments[fragLen-1];
|
||||
}
|
||||
}
|
||||
if(frag) {
|
||||
start = frag.start;
|
||||
//logger.log('find SN matching with pos:' + bufferEnd + ':' + frag.sn);
|
||||
if (fragPrevious && frag.level === fragPrevious.level && frag.sn === fragPrevious.sn) {
|
||||
if (frag.sn < levelDetails.endSN) {
|
||||
frag = fragments[frag.sn + 1 - levelDetails.startSN];
|
||||
logger.log(`SN just loaded, load next one: ${frag.sn}`);
|
||||
} else {
|
||||
// have we reached end of VOD playlist ?
|
||||
if (!levelDetails.live) {
|
||||
// Finalize the media stream
|
||||
this.hls.trigger(Event.BUFFER_EOS);
|
||||
// We might be loading the last fragment but actually the media
|
||||
// is currently processing a seek command and waiting for new data to resume at another point.
|
||||
// Going to ended state while media is seeking can spawn an infinite buffering broken state.
|
||||
if (!isSeeking) {
|
||||
this.state = State.ENDED;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
//logger.log(' loading frag ' + i +',pos/bufEnd:' + pos.toFixed(3) + '/' + bufferEnd.toFixed(3));
|
||||
if ((frag.decryptdata.uri != null) && (frag.decryptdata.key == null)) {
|
||||
logger.log(`Loading key for ${frag.sn} of [${levelDetails.startSN} ,${levelDetails.endSN}],level ${level}`);
|
||||
|
@ -350,8 +347,6 @@ class StreamController extends EventHandler {
|
|||
case State.FRAG_LOADING_WAITING_RETRY:
|
||||
var now = performance.now();
|
||||
var retryDate = this.retryDate;
|
||||
var media = this.media;
|
||||
var isSeeking = media && media.seeking;
|
||||
// if current time is gt than retryDate, or if media seeking let's switch to IDLE state to retry loading
|
||||
if(!retryDate || (now >= retryDate) || isSeeking) {
|
||||
logger.log(`mediaController: retryDate reached, switch back to IDLE state`);
|
||||
|
@ -1024,7 +1019,9 @@ _checkBuffer() {
|
|||
logger.log(`target seek position:${targetSeekPosition}`);
|
||||
}
|
||||
var bufferInfo = BufferHelper.bufferInfo(media,currentTime,0),
|
||||
expectedPlaying = !(media.paused || media.ended || media.seeking || media.buffered.length === 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
|
||||
jumpThreshold = 0.4, // tolerance needed as some browsers stalls playback before reaching buffered range end
|
||||
playheadMoving = currentTime > media.playbackRate*this.lastCurrentTime;
|
||||
|
||||
|
@ -1057,8 +1054,7 @@ _checkBuffer() {
|
|||
var nextBufferStart = bufferInfo.nextStart, delta = nextBufferStart-currentTime;
|
||||
if(nextBufferStart &&
|
||||
(delta < this.config.maxSeekHole) &&
|
||||
(delta > 0) &&
|
||||
!media.seeking) {
|
||||
(delta > 0)) {
|
||||
// next buffer is close ! adjust currentTime to nextBufferStart
|
||||
// this will ensure effective video decoding
|
||||
logger.log(`adjust currentTime from ${media.currentTime} to next buffered @ ${nextBufferStart} + nudge ${this.seekHoleNudgeDuration}`);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue