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
4572a9dbaf
commit
576ca0442c
22 changed files with 472 additions and 303 deletions
|
@ -3,23 +3,22 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
|
||||
class AbrController {
|
||||
class AbrController extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
super(hls, Event.FRAG_LOAD_PROGRESS);
|
||||
this.lastfetchlevel = 0;
|
||||
this._autoLevelCapping = -1;
|
||||
this._nextAutoLevel = -1;
|
||||
this.onflp = this.onFragmentLoadProgress.bind(this);
|
||||
hls.on(Event.FRAG_LOAD_PROGRESS, this.onflp);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.hls.off(Event.FRAG_LOAD_PROGRESS, this.onflp);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onFragmentLoadProgress(event, data) {
|
||||
onFragLoadProgress(data) {
|
||||
var stats = data.stats;
|
||||
if (stats.aborted === undefined) {
|
||||
this.lastfetchduration = (performance.now() - stats.trequest) / 1000;
|
||||
|
|
|
@ -3,35 +3,29 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {logger} from '../utils/logger';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
|
||||
class LevelController {
|
||||
class LevelController extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
this.onml = this.onManifestLoaded.bind(this);
|
||||
this.onll = this.onLevelLoaded.bind(this);
|
||||
this.onerr = this.onError.bind(this);
|
||||
super(hls,
|
||||
Event.MANIFEST_LOADED,
|
||||
Event.LEVEL_LOADED,
|
||||
Event.ERROR);
|
||||
this.ontick = this.tick.bind(this);
|
||||
hls.on(Event.MANIFEST_LOADED, this.onml);
|
||||
hls.on(Event.LEVEL_LOADED, this.onll);
|
||||
hls.on(Event.ERROR, this.onerr);
|
||||
this._manualLevel = this._autoLevelCapping = -1;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
var hls = this.hls;
|
||||
hls.off(Event.MANIFEST_LOADED, this.onml);
|
||||
hls.off(Event.LEVEL_LOADED, this.onll);
|
||||
hls.off(Event.ERROR, this.onerr);
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
}
|
||||
this._manualLevel = -1;
|
||||
}
|
||||
|
||||
onManifestLoaded(event, data) {
|
||||
onManifestLoaded(data) {
|
||||
var levels0 = [], levels = [], bitrateStart, i, bitrateSet = {}, videoCodecFound = false, audioCodecFound = false, hls = this.hls;
|
||||
|
||||
// regroup redundant level together
|
||||
|
@ -166,7 +160,7 @@ class LevelController {
|
|||
this._startLevel = newLevel;
|
||||
}
|
||||
|
||||
onError(event, data) {
|
||||
onError(data) {
|
||||
if(data.fatal) {
|
||||
return;
|
||||
}
|
||||
|
@ -224,7 +218,7 @@ class LevelController {
|
|||
}
|
||||
}
|
||||
|
||||
onLevelLoaded(event, data) {
|
||||
onLevelLoaded(data) {
|
||||
// check if current playlist is a live playlist
|
||||
if (data.details.live && !this.timer) {
|
||||
// if live playlist we will have to reload it periodically
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import Demuxer from '../demux/demuxer';
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {logger} from '../utils/logger';
|
||||
import BinarySearch from '../utils/binary-search';
|
||||
import LevelHelper from '../helper/level-helper';
|
||||
|
@ -23,39 +24,31 @@ const State = {
|
|||
BUFFER_FLUSHING : 8
|
||||
};
|
||||
|
||||
class MSEMediaController {
|
||||
class MSEMediaController extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
super(hls, Event.MEDIA_ATTACHING,
|
||||
Event.MEDIA_DETACHING,
|
||||
Event.MANIFEST_PARSED,
|
||||
Event.LEVEL_LOADED,
|
||||
Event.KEY_LOADED,
|
||||
Event.FRAG_LOADED,
|
||||
Event.FRAG_PARSING_INIT_SEGMENT,
|
||||
Event.FRAG_PARSING_DATA,
|
||||
Event.FRAG_PARSED,
|
||||
Event.ERROR);
|
||||
this.config = hls.config;
|
||||
this.audioCodecSwap = false;
|
||||
this.hls = hls;
|
||||
this.ticks = 0;
|
||||
// Source Buffer listeners
|
||||
this.onsbue = this.onSBUpdateEnd.bind(this);
|
||||
this.onsbe = this.onSBUpdateError.bind(this);
|
||||
// internal listeners
|
||||
this.onmediaatt0 = this.onMediaAttaching.bind(this);
|
||||
this.onmediadet0 = this.onMediaDetaching.bind(this);
|
||||
this.onmp = this.onManifestParsed.bind(this);
|
||||
this.onll = this.onLevelLoaded.bind(this);
|
||||
this.onfl = this.onFragLoaded.bind(this);
|
||||
this.onkl = this.onKeyLoaded.bind(this);
|
||||
this.onis = this.onInitSegment.bind(this);
|
||||
this.onfpg = this.onFragParsing.bind(this);
|
||||
this.onfp = this.onFragParsed.bind(this);
|
||||
this.onerr = this.onError.bind(this);
|
||||
this.ontick = this.tick.bind(this);
|
||||
hls.on(Event.MEDIA_ATTACHING, this.onmediaatt0);
|
||||
hls.on(Event.MEDIA_DETACHING, this.onmediadet0);
|
||||
hls.on(Event.MANIFEST_PARSED, this.onmp);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.stop();
|
||||
var hls = this.hls;
|
||||
hls.off(Event.MEDIA_ATTACHING, this.onmediaatt0);
|
||||
hls.off(Event.MEDIA_DETACHING, this.onmediadet0);
|
||||
hls.off(Event.MANIFEST_PARSED, this.onmp);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
this.state = State.IDLE;
|
||||
}
|
||||
|
||||
|
@ -87,13 +80,6 @@ class MSEMediaController {
|
|||
this.timer = setInterval(this.ontick, 100);
|
||||
this.level = -1;
|
||||
this.fragLoadError = 0;
|
||||
hls.on(Event.FRAG_LOADED, this.onfl);
|
||||
hls.on(Event.FRAG_PARSING_INIT_SEGMENT, this.onis);
|
||||
hls.on(Event.FRAG_PARSING_DATA, this.onfpg);
|
||||
hls.on(Event.FRAG_PARSED, this.onfp);
|
||||
hls.on(Event.ERROR, this.onerr);
|
||||
hls.on(Event.LEVEL_LOADED, this.onll);
|
||||
hls.on(Event.KEY_LOADED, this.onkl);
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
@ -128,14 +114,6 @@ class MSEMediaController {
|
|||
this.demuxer.destroy();
|
||||
this.demuxer = null;
|
||||
}
|
||||
var hls = this.hls;
|
||||
hls.off(Event.FRAG_LOADED, this.onfl);
|
||||
hls.off(Event.FRAG_PARSED, this.onfp);
|
||||
hls.off(Event.FRAG_PARSING_DATA, this.onfpg);
|
||||
hls.off(Event.LEVEL_LOADED, this.onll);
|
||||
hls.off(Event.KEY_LOADED, this.onkl);
|
||||
hls.off(Event.FRAG_PARSING_INIT_SEGMENT, this.onis);
|
||||
hls.off(Event.ERROR, this.onerr);
|
||||
}
|
||||
|
||||
tick() {
|
||||
|
@ -189,7 +167,7 @@ class MSEMediaController {
|
|||
// we are not at playback start, get next load level from level Controller
|
||||
level = hls.nextLoadLevel;
|
||||
}
|
||||
var bufferInfo = this.bufferInfo(pos,0.3),
|
||||
var bufferInfo = this.bufferInfo(pos,this.config.maxBufferHole),
|
||||
bufferLen = bufferInfo.len,
|
||||
bufferEnd = bufferInfo.end,
|
||||
fragPrevious = this.fragPrevious,
|
||||
|
@ -208,7 +186,9 @@ class MSEMediaController {
|
|||
this.level = level;
|
||||
levelDetails = this.levels[level].details;
|
||||
// if level info not retrieved yet, switch state and wait for level retrieval
|
||||
if (typeof levelDetails === 'undefined') {
|
||||
// if live playlist, ensure that new playlist has been refreshed to avoid loading/try to load
|
||||
// a useless and outdated fragment (that might even introduce load error if it is already out of the live playlist)
|
||||
if (typeof levelDetails === 'undefined' || levelDetails.live && this.levelLastLoaded !== level) {
|
||||
this.state = State.WAITING_LEVEL;
|
||||
break;
|
||||
}
|
||||
|
@ -364,7 +344,7 @@ class MSEMediaController {
|
|||
}
|
||||
pos = v.currentTime;
|
||||
var fragLoadedDelay = (frag.expectedLen - frag.loaded) / loadRate;
|
||||
var bufferStarvationDelay = this.bufferInfo(pos,0.3).end - pos;
|
||||
var bufferStarvationDelay = this.bufferInfo(pos,this.config.maxBufferHole).end - pos;
|
||||
var fragLevelNextLoadedDelay = frag.duration * this.levels[hls.nextLoadLevel].bitrate / (8 * loadRate); //bps/Bps
|
||||
/* if we have less than 2 frag duration in buffer and if frag loaded delay is greater than buffer starvation delay
|
||||
... and also bigger than duration needed to load fragment at next level ...*/
|
||||
|
@ -545,6 +525,7 @@ class MSEMediaController {
|
|||
bufferLen = bufferEnd - pos;
|
||||
} else if ((pos + maxHoleDuration) < start) {
|
||||
bufferStartNext = start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {len: bufferLen, start: bufferStart, end: bufferEnd, nextStart : bufferStartNext};
|
||||
|
@ -797,7 +778,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onMediaAttaching(event, data) {
|
||||
onMediaAttaching(data) {
|
||||
var media = this.media = data.media;
|
||||
// setup the media source
|
||||
var ms = this.mediaSource = new MediaSource();
|
||||
|
@ -870,7 +851,7 @@ class MSEMediaController {
|
|||
if (this.state === State.FRAG_LOADING) {
|
||||
// check if currently loaded fragment is inside buffer.
|
||||
//if outside, cancel fragment loading, otherwise do nothing
|
||||
if (this.bufferInfo(this.media.currentTime,0.3).len === 0) {
|
||||
if (this.bufferInfo(this.media.currentTime,this.config.maxBufferHole).len === 0) {
|
||||
logger.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
||||
var fragCurrent = this.fragCurrent;
|
||||
if (fragCurrent) {
|
||||
|
@ -919,7 +900,7 @@ class MSEMediaController {
|
|||
}
|
||||
|
||||
|
||||
onManifestParsed(event, data) {
|
||||
onManifestParsed(data) {
|
||||
var aac = false, heaac = false, codecs;
|
||||
data.levels.forEach(level => {
|
||||
// detect if we have different kind of audio codecs used amongst playlists
|
||||
|
@ -945,13 +926,14 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onLevelLoaded(event,data) {
|
||||
onLevelLoaded(data) {
|
||||
var newDetails = data.details,
|
||||
newLevelId = data.level,
|
||||
curLevel = this.levels[newLevelId],
|
||||
duration = newDetails.totalduration;
|
||||
|
||||
logger.log(`level ${newLevelId} loaded [${newDetails.startSN},${newDetails.endSN}],duration:${duration}`);
|
||||
this.levelLastLoaded = newLevelId;
|
||||
|
||||
if (newDetails.live) {
|
||||
var curDetails = curLevel.details;
|
||||
|
@ -998,7 +980,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onFragLoaded(event, data) {
|
||||
onFragLoaded(data) {
|
||||
var fragCurrent = this.fragCurrent;
|
||||
if (this.state === State.FRAG_LOADING &&
|
||||
fragCurrent &&
|
||||
|
@ -1039,7 +1021,7 @@ class MSEMediaController {
|
|||
this.fragLoadError = 0;
|
||||
}
|
||||
|
||||
onInitSegment(event, data) {
|
||||
onFragParsingInitSegment(data) {
|
||||
if (this.state === State.PARSING) {
|
||||
// check if codecs have been explicitely defined in the master playlist for this level;
|
||||
// if yes use these ones instead of the ones parsed from the demux
|
||||
|
@ -1098,7 +1080,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onFragParsing(event, data) {
|
||||
onFragParsingData(data) {
|
||||
if (this.state === State.PARSING) {
|
||||
this.tparse2 = Date.now();
|
||||
var level = this.levels[this.level],
|
||||
|
@ -1115,7 +1097,7 @@ class MSEMediaController {
|
|||
//trigger handler right now
|
||||
this.tick();
|
||||
} else {
|
||||
logger.warn(`not in PARSING state, discarding ${event}`);
|
||||
logger.warn(`not in PARSING state, ignoring FRAG_PARSING_DATA event`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1128,7 +1110,7 @@ class MSEMediaController {
|
|||
}
|
||||
}
|
||||
|
||||
onError(event, data) {
|
||||
onError(data) {
|
||||
switch(data.details) {
|
||||
case ErrorDetails.FRAG_LOAD_ERROR:
|
||||
case ErrorDetails.FRAG_LOAD_TIMEOUT:
|
||||
|
@ -1153,7 +1135,7 @@ class MSEMediaController {
|
|||
logger.error(`mediaController: ${data.details} reaches max retry, redispatch as fatal ...`);
|
||||
// redispatch same error but with fatal set to true
|
||||
data.fatal = true;
|
||||
this.hls.trigger(event, data);
|
||||
this.hls.trigger(Event.ERROR, data);
|
||||
this.state = State.ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -1216,14 +1198,14 @@ _checkBuffer() {
|
|||
// playhead moving or media not playing
|
||||
jumpThreshold = 0;
|
||||
} else {
|
||||
logger.trace('playback seems stuck');
|
||||
logger.log('playback seems stuck');
|
||||
}
|
||||
// if we are below threshold, try to jump if next buffer range is close
|
||||
if(bufferInfo.len <= jumpThreshold) {
|
||||
// no buffer available @ currentTime, check if next buffer is close (more than 5ms diff but within a 300 ms range)
|
||||
// no buffer available @ currentTime, check if next buffer is close (more than 5ms diff but within a config.maxSeekHole second range)
|
||||
var nextBufferStart = bufferInfo.nextStart, delta = nextBufferStart-currentTime;
|
||||
if(nextBufferStart &&
|
||||
(delta < 0.3) &&
|
||||
(delta < this.config.maxSeekHole) &&
|
||||
(delta > 0.005) &&
|
||||
!media.seeking) {
|
||||
// next buffer is close ! adjust currentTime to nextBufferStart
|
||||
|
|
66
dashboard-ui/bower_components/hls.js/src/event-handler.js
vendored
Normal file
66
dashboard-ui/bower_components/hls.js/src/event-handler.js
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
*
|
||||
* All objects in the event handling chain should inherit from this class
|
||||
*
|
||||
*/
|
||||
|
||||
//import {logger} from './utils/logger';
|
||||
|
||||
class EventHandler {
|
||||
|
||||
constructor(hls, ...events) {
|
||||
this.hls = hls;
|
||||
this.onEvent = this.onEvent.bind(this);
|
||||
this.handledEvents = events;
|
||||
this.useGenericHandler = true;
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.unregisterListeners();
|
||||
}
|
||||
|
||||
isEventHandler() {
|
||||
return typeof this.handledEvents === 'object' && this.handledEvents.length && typeof this.onEvent === 'function';
|
||||
}
|
||||
|
||||
registerListeners() {
|
||||
if (this.isEventHandler()) {
|
||||
this.handledEvents.forEach(function(event) {
|
||||
if (event === 'hlsEventGeneric') {
|
||||
throw new Error('Forbidden event name: ' + event);
|
||||
}
|
||||
this.hls.on(event, this.onEvent);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
unregisterListeners() {
|
||||
if (this.isEventHandler()) {
|
||||
this.handledEvents.forEach(function(event) {
|
||||
this.hls.off(event, this.onEvent);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* arguments: event (string), data (any)
|
||||
*/
|
||||
onEvent(event, data) {
|
||||
this.onEventGeneric(event, data);
|
||||
}
|
||||
|
||||
onEventGeneric(event, data) {
|
||||
var eventToFunction = function(event, data) {
|
||||
var funcName = 'on' + event.replace('hls', '');
|
||||
if (typeof this[funcName] !== 'function') {
|
||||
throw new Error(`Event ${event} has no generic handler in this ${this.constructor.name} class (tried ${funcName})`);
|
||||
}
|
||||
return this[funcName].bind(this, data);
|
||||
};
|
||||
eventToFunction.call(this, event, data).call();
|
||||
}
|
||||
}
|
||||
|
||||
export default EventHandler;
|
|
@ -1,4 +1,4 @@
|
|||
export default {
|
||||
module.exports = {
|
||||
// fired before MediaSource is attaching to media element - data: { media }
|
||||
MEDIA_ATTACHING: 'hlsMediaAttaching',
|
||||
// fired when MediaSource has been succesfully attached to media element - data: { }
|
||||
|
@ -20,7 +20,7 @@ export default {
|
|||
// fired when a level's details have been updated based on previous details, after it has been loaded. - data: { details : levelDetails object, level : id of updated level }
|
||||
LEVEL_UPDATED: 'hlsLevelUpdated',
|
||||
// fired when a level's PTS information has been updated after parsing a fragment - data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment }
|
||||
LEVEL_PTS_UPDATED: 'hlsPTSUpdated',
|
||||
LEVEL_PTS_UPDATED: 'hlsLevelPtsUpdated',
|
||||
// fired when a level switch is requested - data: { level : id of new level }
|
||||
LEVEL_SWITCH: 'hlsLevelSwitch',
|
||||
// fired when a fragment loading starts - data: { frag : fragment object}
|
||||
|
@ -34,7 +34,7 @@ export default {
|
|||
// fired when Init Segment has been extracted from fragment - data: { moov : moov MP4 box, codecs : codecs found while parsing fragment}
|
||||
FRAG_PARSING_INIT_SEGMENT: 'hlsFragParsingInitSegment',
|
||||
// fired when parsing id3 is completed - data: { samples : [ id3 samples pes ] }
|
||||
FRAG_PARSING_METADATA: 'hlsFraParsingMetadata',
|
||||
FRAG_PARSING_METADATA: 'hlsFragParsingMetadata',
|
||||
// fired when moof/mdat have been extracted from fragment - data: { moof : moof MP4 box, mdat : mdat MP4 box}
|
||||
FRAG_PARSING_DATA: 'hlsFragParsingData',
|
||||
// fired when fragment parsing is completed - data: undefined
|
||||
|
@ -44,7 +44,7 @@ export default {
|
|||
// fired when fragment matching with current media position is changing - data : { frag : fragment object }
|
||||
FRAG_CHANGED: 'hlsFragChanged',
|
||||
// Identifier for a FPS drop event - data: {curentDropped, currentDecoded, totalDroppedFrames}
|
||||
FPS_DROP: 'hlsFPSDrop',
|
||||
FPS_DROP: 'hlsFpsDrop',
|
||||
// Identifier for an error event - data: { type : error type, details : error details, fatal : if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data}
|
||||
ERROR: 'hlsError',
|
||||
// fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example
|
||||
|
|
|
@ -41,6 +41,8 @@ class Hls {
|
|||
debug: false,
|
||||
maxBufferLength: 30,
|
||||
maxBufferSize: 60 * 1000 * 1000,
|
||||
maxBufferHole: 0.3,
|
||||
maxSeekHole: 2,
|
||||
liveSyncDurationCount:3,
|
||||
liveMaxLatencyDurationCount: Infinity,
|
||||
maxMaxBufferLength: 600,
|
||||
|
|
|
@ -3,14 +3,13 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
|
||||
class FragmentLoader {
|
||||
class FragmentLoader extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
this.onfl = this.onFragLoading.bind(this);
|
||||
hls.on(Event.FRAG_LOADING, this.onfl);
|
||||
super(hls, Event.FRAG_LOADING);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -18,10 +17,10 @@ class FragmentLoader {
|
|||
this.loader.destroy();
|
||||
this.loader = null;
|
||||
}
|
||||
this.hls.off(Event.FRAG_LOADING, this.onfl);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onFragLoading(event, data) {
|
||||
onFragLoading(data) {
|
||||
var frag = data.frag;
|
||||
this.frag = frag;
|
||||
this.frag.loaded = 0;
|
||||
|
|
|
@ -3,16 +3,15 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
|
||||
class KeyLoader {
|
||||
class KeyLoader extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
super(hls, Event.KEY_LOADING);
|
||||
this.decryptkey = null;
|
||||
this.decrypturl = null;
|
||||
this.ondkl = this.onDecryptKeyLoading.bind(this);
|
||||
hls.on(Event.KEY_LOADING, this.ondkl);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -20,10 +19,10 @@ class KeyLoader {
|
|||
this.loader.destroy();
|
||||
this.loader = null;
|
||||
}
|
||||
this.hls.off(Event.KEY_LOADING, this.ondkl);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onDecryptKeyLoading(event, data) {
|
||||
onKeyLoading(data) {
|
||||
var frag = this.frag = data.frag,
|
||||
decryptdata = frag.decryptdata,
|
||||
uri = decryptdata.uri;
|
||||
|
|
|
@ -3,19 +3,18 @@
|
|||
*/
|
||||
|
||||
import Event from '../events';
|
||||
import EventHandler from '../event-handler';
|
||||
import {ErrorTypes, ErrorDetails} from '../errors';
|
||||
import URLHelper from '../utils/url';
|
||||
import AttrList from '../utils/attr-list';
|
||||
//import {logger} from '../utils/logger';
|
||||
|
||||
class PlaylistLoader {
|
||||
class PlaylistLoader extends EventHandler {
|
||||
|
||||
constructor(hls) {
|
||||
this.hls = hls;
|
||||
this.onml = this.onManifestLoading.bind(this);
|
||||
this.onll = this.onLevelLoading.bind(this);
|
||||
hls.on(Event.MANIFEST_LOADING, this.onml);
|
||||
hls.on(Event.LEVEL_LOADING, this.onll);
|
||||
super(hls,
|
||||
Event.MANIFEST_LOADING,
|
||||
Event.LEVEL_LOADING);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -24,15 +23,14 @@ class PlaylistLoader {
|
|||
this.loader = null;
|
||||
}
|
||||
this.url = this.id = null;
|
||||
this.hls.off(Event.MANIFEST_LOADING, this.onml);
|
||||
this.hls.off(Event.LEVEL_LOADING, this.onll);
|
||||
EventHandler.prototype.destroy.call(this);
|
||||
}
|
||||
|
||||
onManifestLoading(event, data) {
|
||||
onManifestLoading(data) {
|
||||
this.load(data.url, null);
|
||||
}
|
||||
|
||||
onLevelLoading(event, data) {
|
||||
onLevelLoading(data) {
|
||||
this.load(data.url, data.level, data.id);
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ class MP4Remuxer {
|
|||
mdat, moof,
|
||||
firstPTS, firstDTS, lastDTS,
|
||||
pts, dts, ptsnorm, dtsnorm,
|
||||
flags,
|
||||
samples = [];
|
||||
/* concatenate the video data and construct the mdat in place
|
||||
(need 8 more bytes to fill length and mpdat type) */
|
||||
|
@ -152,7 +153,7 @@ class MP4Remuxer {
|
|||
dts = avcSample.dts - this._initDTS;
|
||||
// ensure DTS is not bigger than PTS
|
||||
dts = Math.min(pts,dts);
|
||||
//logger.log(`Video/PTS/DTS:${pts}/${dts}`);
|
||||
//logger.log(`Video/PTS/DTS:${Math.round(pts/90)}/${Math.round(dts/90)}`);
|
||||
// if not first AVC sample of video track, normalize PTS/DTS with previous sample value
|
||||
// and ensure that sample duration is positive
|
||||
if (lastDTS !== undefined) {
|
||||
|
@ -201,13 +202,14 @@ class MP4Remuxer {
|
|||
degradPrio: 0
|
||||
}
|
||||
};
|
||||
flags = mp4Sample.flags;
|
||||
if (avcSample.key === true) {
|
||||
// the current sample is a key frame
|
||||
mp4Sample.flags.dependsOn = 2;
|
||||
mp4Sample.flags.isNonSync = 0;
|
||||
flags.dependsOn = 2;
|
||||
flags.isNonSync = 0;
|
||||
} else {
|
||||
mp4Sample.flags.dependsOn = 1;
|
||||
mp4Sample.flags.isNonSync = 1;
|
||||
flags.dependsOn = 1;
|
||||
flags.isNonSync = 1;
|
||||
}
|
||||
samples.push(mp4Sample);
|
||||
lastDTS = dtsnorm;
|
||||
|
@ -222,7 +224,7 @@ class MP4Remuxer {
|
|||
track.len = 0;
|
||||
track.nbNalu = 0;
|
||||
if(samples.length && navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
|
||||
var flags = samples[0].flags;
|
||||
flags = samples[0].flags;
|
||||
// chrome workaround, mark first sample as being a Random Access Point to avoid sourcebuffer append issue
|
||||
// https://code.google.com/p/chromium/issues/detail?id=229412
|
||||
flags.dependsOn = 2;
|
||||
|
@ -270,7 +272,7 @@ class MP4Remuxer {
|
|||
unit = aacSample.unit;
|
||||
pts = aacSample.pts - this._initDTS;
|
||||
dts = aacSample.dts - this._initDTS;
|
||||
//logger.log(`Audio/PTS:${aacSample.pts.toFixed(0)}`);
|
||||
//logger.log(`Audio/PTS:${Math.round(pts/90)}`);
|
||||
// if not first sample
|
||||
if (lastDTS !== undefined) {
|
||||
ptsnorm = this._PTSNormalize(pts, lastDTS);
|
||||
|
|
|
@ -49,7 +49,7 @@ class XhrLoader {
|
|||
|
||||
loadInternal() {
|
||||
var xhr = this.loader = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = this.statechange.bind(this);
|
||||
xhr.onloadend = this.loadend.bind(this);
|
||||
xhr.onprogress = this.loadprogress.bind(this);
|
||||
|
||||
xhr.open('GET', this.url, true);
|
||||
|
@ -65,13 +65,12 @@ class XhrLoader {
|
|||
xhr.send();
|
||||
}
|
||||
|
||||
statechange(event) {
|
||||
loadend(event) {
|
||||
var xhr = event.currentTarget,
|
||||
status = xhr.status,
|
||||
stats = this.stats;
|
||||
// don't proceed if xhr has been aborted
|
||||
// 4 = Response from server has been completely loaded.
|
||||
if (!stats.aborted && xhr.readyState === 4) {
|
||||
if (!stats.aborted) {
|
||||
// http status between 200 to 299 are all successful
|
||||
if (status >= 200 && status < 300) {
|
||||
window.clearTimeout(this.timeoutHandle);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue