Socket
Socket
Sign inDemoInstall

xgplayer-flv.js

Package Overview
Dependencies
Maintainers
3
Versions
147
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

xgplayer-flv.js - npm Package Compare versions

Comparing version 1.0.4 to 1.0.5

2

package.json
{
"name": "xgplayer-flv.js",
"version": "1.0.4",
"version": "1.0.5",
"description": "web video player",

@@ -5,0 +5,0 @@ "main": "./dist/index.js",

@@ -19,700 +19,724 @@ /*

import EventEmitter from 'events';
import Log from '../utils/logger.js';
import Browser from '../utils/browser.js';
import PlayerEvents from './player-events.js';
import Transmuxer from '../core/transmuxer.js';
import TransmuxingEvents from '../core/transmuxing-events.js';
import MSEController from '../core/mse-controller.js';
import MSEEvents from '../core/mse-events.js';
import {ErrorTypes, ErrorDetails} from './player-errors.js';
import {createDefaultConfig} from '../config.js';
import {InvalidArgumentException, IllegalStateException} from '../utils/exception.js';
import EventEmitter from 'events'
import Log from '../utils/logger.js'
import Browser from '../utils/browser.js'
import PlayerEvents from './player-events.js'
import Transmuxer from '../core/transmuxer.js'
import TransmuxingEvents from '../core/transmuxing-events.js'
import MSEController from '../core/mse-controller.js'
import MSEEvents from '../core/mse-events.js'
import {ErrorTypes, ErrorDetails} from './player-errors.js'
import {createDefaultConfig} from '../config.js'
import {InvalidArgumentException, IllegalStateException} from '../utils/exception.js'
/* eslint-disable */
class FlvPlayer {
constructor (mediaDataSource, config) {
this.TAG = 'FlvPlayer'
this._type = 'FlvPlayer'
this._emitter = new EventEmitter()
constructor(mediaDataSource, config) {
this.TAG = 'FlvPlayer';
this._type = 'FlvPlayer';
this._emitter = new EventEmitter();
this._config = createDefaultConfig()
if (typeof config === 'object') {
Object.assign(this._config, config)
}
this._config = createDefaultConfig();
if (typeof config === 'object') {
Object.assign(this._config, config);
}
if (mediaDataSource.type.toLowerCase() !== 'flv') {
throw new InvalidArgumentException('FlvPlayer requires an flv MediaDataSource input!')
}
if (mediaDataSource.type.toLowerCase() !== 'flv') {
throw new InvalidArgumentException('FlvPlayer requires an flv MediaDataSource input!');
}
if (mediaDataSource.isLive === true) {
this._config.isLive = true
}
if (mediaDataSource.isLive === true) {
this._config.isLive = true;
}
this.e = {
onvLoadedMetadata: this._onvLoadedMetadata.bind(this),
onvSeeking: this._onvSeeking.bind(this),
onvCanPlay: this._onvCanPlay.bind(this),
onvStalled: this._onvStalled.bind(this),
onvProgress: this._onvProgress.bind(this)
}
this.e = {
onvLoadedMetadata: this._onvLoadedMetadata.bind(this),
onvSeeking: this._onvSeeking.bind(this),
onvCanPlay: this._onvCanPlay.bind(this),
onvStalled: this._onvStalled.bind(this),
onvProgress: this._onvProgress.bind(this)
};
if (window.performance && window.performance.now) {
this._now = window.performance.now.bind(window.performance)
} else {
this._now = Date.now
}
if (self.performance && self.performance.now) {
this._now = self.performance.now.bind(self.performance);
} else {
this._now = Date.now;
}
this._pendingSeekTime = null // in seconds
this._requestSetTime = false
this._seekpointRecord = null
this._progressChecker = null
this._pendingSeekTime = null; // in seconds
this._requestSetTime = false;
this._seekpointRecord = null;
this._progressChecker = null;
this._mediaDataSource = mediaDataSource
this._mediaElement = null
this._msectl = null
this._transmuxer = null
this._mediaDataSource = mediaDataSource;
this._mediaElement = null;
this._msectl = null;
this._transmuxer = null;
this._mseSourceOpened = false
this._hasPendingLoad = false
this._receivedCanPlay = false
this._mseSourceOpened = false;
this._hasPendingLoad = false;
this._receivedCanPlay = false;
this._mediaInfo = null
this._statisticsInfo = null
this._mediaInfo = null;
this._statisticsInfo = null;
let chromeNeedIDRFix = (Browser.chrome &&
(Browser.version.major < 50 ||
(Browser.version.major === 50 && Browser.version.build < 2661)))
this._alwaysSeekKeyframe = !!((chromeNeedIDRFix || Browser.msedge || Browser.msie))
let chromeNeedIDRFix = (Browser.chrome &&
(Browser.version.major < 50 ||
(Browser.version.major === 50 && Browser.version.build < 2661)));
this._alwaysSeekKeyframe = (chromeNeedIDRFix || Browser.msedge || Browser.msie) ? true : false;
if (this._alwaysSeekKeyframe) {
this._config.accurateSeek = false
}
this._tempPendingSegments = {
audio: [],
video: []
}
this._definitionRetryTimes = 0
}
if (this._alwaysSeekKeyframe) {
this._config.accurateSeek = false;
}
this._tempPendingSegments = {
audio: [],
video: [],
};
this._definitionRetryTimes = 0;
destroy () {
if (this._progressChecker != null) {
window.clearInterval(this._progressChecker)
this._progressChecker = null
}
if (this._transmuxer) {
this.unload()
}
if (this._mediaElement) {
this.detachMediaElement()
}
this.e = null
this._mediaDataSource = null
destroy() {
if (this._progressChecker != null) {
window.clearInterval(this._progressChecker);
this._progressChecker = null;
}
if (this._transmuxer) {
this.unload();
}
if (this._mediaElement) {
this.detachMediaElement();
}
this.e = null;
this._mediaDataSource = null;
this._emitter.removeAllListeners()
this._emitter = null
}
this._emitter.removeAllListeners();
this._emitter = null;
on (event, listener) {
if (event === PlayerEvents.MEDIA_INFO) {
if (this._mediaInfo != null) {
Promise.resolve().then(() => {
this._emitter.emit(PlayerEvents.MEDIA_INFO, this.mediaInfo)
})
}
} else if (event === PlayerEvents.STATISTICS_INFO) {
if (this._statisticsInfo != null) {
Promise.resolve().then(() => {
this._emitter.emit(PlayerEvents.STATISTICS_INFO, this.statisticsInfo)
})
}
}
this._emitter.addListener(event, listener)
}
on(event, listener) {
if (event === PlayerEvents.MEDIA_INFO) {
if (this._mediaInfo != null) {
Promise.resolve().then(() => {
this._emitter.emit(PlayerEvents.MEDIA_INFO, this.mediaInfo);
});
}
} else if (event === PlayerEvents.STATISTICS_INFO) {
if (this._statisticsInfo != null) {
Promise.resolve().then(() => {
this._emitter.emit(PlayerEvents.STATISTICS_INFO, this.statisticsInfo);
});
}
}
this._emitter.addListener(event, listener);
off (event, listener) {
this._emitter.removeListener(event, listener)
}
attachMediaElement (mediaElement) {
this._mediaElement = mediaElement
mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata)
mediaElement.addEventListener('seeking', this.e.onvSeeking)
mediaElement.addEventListener('canplay', this.e.onvCanPlay)
mediaElement.addEventListener('stalled', this.e.onvStalled)
mediaElement.addEventListener('progress', this.e.onvProgress)
this._msectl = new MSEController(this._config)
this._msectl.on(MSEEvents.UPDATE_END, this._onmseUpdateEnd.bind(this))
this._msectl.on(MSEEvents.BUFFER_FULL, this._onmseBufferFull.bind(this))
this._msectl.on(MSEEvents.SOURCE_OPEN, () => {
this._mseSourceOpened = true
if (this._hasPendingLoad) {
this._hasPendingLoad = false
this.load()
}
})
this._msectl.on(MSEEvents.ERROR, (info) => {
this._emitter.emit(PlayerEvents.ERROR,
ErrorTypes.MEDIA_ERROR,
ErrorDetails.MEDIA_MSE_ERROR,
info
)
})
this._msectl.attachMediaElement(mediaElement)
if (this._pendingSeekTime != null) {
try {
mediaElement.currentTime = this._pendingSeekTime
this._pendingSeekTime = null
} catch (e) {
// IE11 may throw InvalidStateError if readyState === 0
// We can defer set currentTime operation after loadedmetadata
}
}
}
off(event, listener) {
this._emitter.removeListener(event, listener);
detachMediaElement () {
if (this._mediaElement) {
this._msectl.detachMediaElement()
this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata)
this._mediaElement.removeEventListener('seeking', this.e.onvSeeking)
this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay)
this._mediaElement.removeEventListener('stalled', this.e.onvStalled)
this._mediaElement.removeEventListener('progress', this.e.onvProgress)
this._mediaElement = null
}
if (this._msectl) {
this._msectl.destroy()
this._msectl = null
}
}
attachMediaElement(mediaElement) {
this._mediaElement = mediaElement;
mediaElement.addEventListener('loadedmetadata', this.e.onvLoadedMetadata);
mediaElement.addEventListener('seeking', this.e.onvSeeking);
mediaElement.addEventListener('canplay', this.e.onvCanPlay);
mediaElement.addEventListener('stalled', this.e.onvStalled);
mediaElement.addEventListener('progress', this.e.onvProgress);
onDefinitionChange (url, expectTime = 3) {
// setTimeout(() => {
// if (!this.isDefinitionDataReady && this._definitionRetryTimes < 3) {
// this._definitionRetryTimes += 1
// this.onDefinitionChange(url, expectTime)
// } else if (this.isDefinitionDataReady) {
// if (this._transmuxer !== this._tempTransmuxer) {
// this._transmuxer.destroy()
// this._transmuxer = this._tempTransmuxer
// let currentTime = this._mediaElement.currentTime
// this._tempTransmuxer.seek(currentTime * 1000)
// }
// Object.keys(this._tempPendingSegments).forEach(key => {
// this._msectl._pendingSegments[key] = this._tempPendingSegments[key]
// })
// this._tempPendingSegments = {
// audio: [],
// video: []
// }
//
// this._definitionRetryTimes = 0
// } else if (this._definitionRetryTimes >= 3) {
// this._definitionRetryTimes = 0
// if (this._tempTransmuxer) {
// this._tempTransmuxer.destroy()
// this._tempTransmuxer = null
// this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.NETWORK_ERROR, '', '清晰度切换失败!')
// }
// this._definitionRetryTimes = 0
// }
// this._tempPendingSegments = {
// audio: [],
// video: []
// }
// }, expectTime * 1000)
this._msectl = new MSEController(this._config);
this._mediaDataSource.segments[0].url = url
this._tempMds = Object.assign({}, this._mediaDataSource, {url})
this._msectl.on(MSEEvents.UPDATE_END, this._onmseUpdateEnd.bind(this));
this._msectl.on(MSEEvents.BUFFER_FULL, this._onmseBufferFull.bind(this));
this._msectl.on(MSEEvents.SOURCE_OPEN, () => {
this._mseSourceOpened = true;
if (this._hasPendingLoad) {
this._hasPendingLoad = false;
this.load();
}
});
this._msectl.on(MSEEvents.ERROR, (info) => {
this._emitter.emit(PlayerEvents.ERROR,
ErrorTypes.MEDIA_ERROR,
ErrorDetails.MEDIA_MSE_ERROR,
info
);
});
this._tempTransmuxer = new Transmuxer(this._tempMds, this._config)
this._msectl.attachMediaElement(mediaElement);
this._tempTransmuxer.on(TransmuxingEvents.INIT_SEGMENT, (type, is) => {
if (!this._config.isLive) {
this._tempPendingSegments[type] = [is]
// this._msectl.appendInitSegment(is)
if (this._transmuxer !== this._tempTransmuxer && this._tempTransmuxer) {
const currentTime = this._mediaElement.currentTime
this._tempTransmuxer.seek(currentTime * 1000)
}
// if (this._transmuxer !== this._tempTransmuxer) {
// this._transmuxer.destroy()
// }
// this._transmuxer = this._tempTransmuxer
} else {
this._msectl.doClearSourceBuffer()
this._msectl.appendInitSegment(is)
if (this._transmuxer !== this._tempTransmuxer) {
this._transmuxer.destroy()
}
this._transmuxer = this._tempTransmuxer
}
})
if (this._pendingSeekTime != null) {
try {
mediaElement.currentTime = this._pendingSeekTime;
this._pendingSeekTime = null;
} catch (e) {
// IE11 may throw InvalidStateError if readyState === 0
// We can defer set currentTime operation after loadedmetadata
this._tempTransmuxer.on(TransmuxingEvents.MEDIA_SEGMENT, (type, ms) => {
if (!this._config.isLive) {
if (!this._tempTransmuxer) {
this._msectl.appendMediaSegment(ms)
} else {
this._tempPendingSegments[type] && this._tempPendingSegments[type].push(ms)
if (this.isDefinitionDataReady) {
Object.keys(this._tempPendingSegments).forEach(key => {
this._msectl._pendingSegments[key] = this._tempPendingSegments[key]
})
this._tempPendingSegments = {
audio: [],
video: []
}
this._transmuxer.destroy()
this._transmuxer = this._tempTransmuxer
delete this._tempTransmuxer
}
}
}
} else {
this._msectl.appendMediaSegment(ms)
}
detachMediaElement() {
if (this._mediaElement) {
this._msectl.detachMediaElement();
this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
this._mediaElement.removeEventListener('seeking', this.e.onvSeeking);
this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
this._mediaElement.removeEventListener('stalled', this.e.onvStalled);
this._mediaElement.removeEventListener('progress', this.e.onvProgress);
this._mediaElement = null;
// lazyLoad check
if (this._config.lazyLoad && !this._config.isLive) {
let currentTime = this._mediaElement.currentTime
if (ms.info.endDts >= (currentTime + this._config.lazyLoadMaxDuration) * 1000) {
if (this._progressChecker == null) {
Log.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task')
this._suspendTransmuxer()
}
}
if (this._msectl) {
this._msectl.destroy();
this._msectl = null;
}
}
}
})
this._tempTransmuxer.on(TransmuxingEvents.LOADING_COMPLETE, () => {
this._msectl.endOfStream()
this._emitter.emit(PlayerEvents.LOADING_COMPLETE)
})
this._tempTransmuxer.on(TransmuxingEvents.RECOVERED_EARLY_EOF, () => {
this._emitter.emit(PlayerEvents.RECOVERED_EARLY_EOF)
})
this._tempTransmuxer.on(TransmuxingEvents.IO_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.NETWORK_ERROR, detail, info)
})
this._tempTransmuxer.on(TransmuxingEvents.DEMUX_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.MEDIA_ERROR, detail, {code: -1, msg: info})
})
this._tempTransmuxer.on(TransmuxingEvents.MEDIA_INFO, (mediaInfo) => {
this._mediaInfo = mediaInfo
this._tempTransmuxer.seek((this._mediaElement.currentTime + expectTime) * 1000)
this._emitter.emit(PlayerEvents.MEDIA_INFO, Object.assign({}, mediaInfo))
})
this._tempTransmuxer.on(TransmuxingEvents.STATISTICS_INFO, (statInfo) => {
this._statisticsInfo = this._fillStatisticsInfo(statInfo)
this._emitter.emit(PlayerEvents.STATISTICS_INFO, Object.assign({}, this._statisticsInfo))
})
this._tempTransmuxer.on(TransmuxingEvents.RECOMMEND_SEEKPOINT, (milliseconds) => {
if (this._transmuxer === this._tempTransmuxer && this._mediaElement && !this._config.accurateSeek) {
this._requestSetTime = true
this._mediaElement.currentTime = milliseconds / 1000
}
})
onDefinitionChange(url, expectTime = 3) {
setTimeout(() => {
if (!this.isDefinitionDataReady && this._definitionRetryTimes < 3) {
this._definitionRetryTimes += 1;
this.onDefinitionChange(url, expectTime);
} else if (this.isDefinitionDataReady) {
this._transmuxer.destroy();
this._tempTransmuxer.open()
}
Object.keys(this._tempPendingSegments).forEach(key => {
this._msectl._pendingSegments[key] = this._tempPendingSegments[key];
});
this._tempPendingSegments = {
audio: [],
video: [],
};
this._transmuxer = this._tempTransmuxer;
this._definitionRetryTimes = 0;
} else if (this._definitionRetryTimes >= 3) {
this._definitionRetryTimes = 0;
if (this._tempTransmuxer) {
this._tempTransmuxer.destroy();
this._tempTransmuxer = null;
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.NETWORK_ERROR, '', '清晰度切换失败!');
}
this._definitionRetryTimes = 0;
}
this._tempPendingSegments = {
audio: [],
video: [],
};
}, expectTime * 1000);
load () {
if (!this._mediaElement) {
throw new IllegalStateException('HTMLMediaElement must be attached before load()!')
}
if (this._transmuxer) {
throw new IllegalStateException('FlvPlayer.load() has been called, please call unload() first!')
}
if (this._hasPendingLoad) {
return
}
this._mediaDataSource.segments[0].url = url;
this._tempMds = Object.assign({}, this._mediaDataSource, { url });
if (this._config.deferLoadAfterSourceOpen && this._mseSourceOpened === false) {
this._hasPendingLoad = true
return
}
this._tempTransmuxer = new Transmuxer(this._tempMds, this._config);
if (this._mediaElement.readyState > 0) {
this._requestSetTime = true
// IE11 may throw InvalidStateError if readyState === 0
this._mediaElement.currentTime = 0
}
this._transmuxer = new Transmuxer(this._mediaDataSource, this._config)
this._tempTransmuxer.on(TransmuxingEvents.INIT_SEGMENT, (type, is) => {
if (!this._config.isLive) {
this._tempPendingSegments[type] = [is];
} else {
this._msectl.doClearSourceBuffer();
this._msectl.appendInitSegment(is);
if (this._transmuxer !== this._tempTransmuxer) {
this._transmuxer.destroy();
}
this._transmuxer = this._tempTransmuxer;
}
});
this._transmuxer.on(TransmuxingEvents.INIT_SEGMENT, (type, is) => {
this._msectl.appendInitSegment(is)
})
this._transmuxer.on(TransmuxingEvents.MEDIA_SEGMENT, (type, ms) => {
this._msectl.appendMediaSegment(ms)
this._tempTransmuxer.on(TransmuxingEvents.MEDIA_SEGMENT, (type, ms) => {
if (!this._config.isLive) {
if (this._transmuxer === this._tempTransmuxer) {
this._msectl.appendMediaSegment(ms);
} else {
this._tempPendingSegments[type] && this._tempPendingSegments[type].push(ms);
}
} else {
this._msectl.appendMediaSegment(ms);
}
// lazyLoad check
if (this._config.lazyLoad && !this._config.isLive) {
let currentTime = this._mediaElement.currentTime
if (ms.info.endDts >= (currentTime + this._config.lazyLoadMaxDuration) * 1000) {
if (this._progressChecker == null) {
Log.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task')
this._suspendTransmuxer()
}
}
}
})
this._transmuxer.on(TransmuxingEvents.LOADING_COMPLETE, () => {
this._msectl.endOfStream()
this._emitter.emit(PlayerEvents.LOADING_COMPLETE)
})
this._transmuxer.on(TransmuxingEvents.RECOVERED_EARLY_EOF, () => {
this._emitter.emit(PlayerEvents.RECOVERED_EARLY_EOF)
})
this._transmuxer.on(TransmuxingEvents.IO_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.NETWORK_ERROR, detail, info)
})
this._transmuxer.on(TransmuxingEvents.DEMUX_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.MEDIA_ERROR, detail, {code: -1, msg: info})
})
this._transmuxer.on(TransmuxingEvents.MEDIA_INFO, (mediaInfo) => {
this._mediaInfo = mediaInfo
this._emitter.emit(PlayerEvents.MEDIA_INFO, Object.assign({}, mediaInfo))
})
this._transmuxer.on(TransmuxingEvents.STATISTICS_INFO, (statInfo) => {
this._statisticsInfo = this._fillStatisticsInfo(statInfo)
this._emitter.emit(PlayerEvents.STATISTICS_INFO, Object.assign({}, this._statisticsInfo))
})
this._transmuxer.on(TransmuxingEvents.RECOMMEND_SEEKPOINT, (milliseconds) => {
if (this._mediaElement && !this._config.accurateSeek) {
this._requestSetTime = true
this._mediaElement.currentTime = milliseconds / 1000
}
})
// lazyLoad check
if (this._config.lazyLoad && !this._config.isLive) {
let currentTime = this._mediaElement.currentTime;
if (ms.info.endDts >= (currentTime + this._config.lazyLoadMaxDuration) * 1000) {
if (this._progressChecker == null) {
Log.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
this._suspendTransmuxer();
}
}
}
});
this._tempTransmuxer.on(TransmuxingEvents.LOADING_COMPLETE, () => {
this._msectl.endOfStream();
this._emitter.emit(PlayerEvents.LOADING_COMPLETE);
});
this._tempTransmuxer.on(TransmuxingEvents.RECOVERED_EARLY_EOF, () => {
this._emitter.emit(PlayerEvents.RECOVERED_EARLY_EOF);
});
this._tempTransmuxer.on(TransmuxingEvents.IO_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.NETWORK_ERROR, detail, info);
});
this._tempTransmuxer.on(TransmuxingEvents.DEMUX_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.MEDIA_ERROR, detail, {code: -1, msg: info});
});
this._tempTransmuxer.on(TransmuxingEvents.MEDIA_INFO, (mediaInfo) => {
this._mediaInfo = mediaInfo;
this._tempTransmuxer.seek((this._mediaElement.currentTime + expectTime) * 1000);
this._emitter.emit(PlayerEvents.MEDIA_INFO, Object.assign({}, mediaInfo));
});
this._tempTransmuxer.on(TransmuxingEvents.STATISTICS_INFO, (statInfo) => {
this._statisticsInfo = this._fillStatisticsInfo(statInfo);
this._emitter.emit(PlayerEvents.STATISTICS_INFO, Object.assign({}, this._statisticsInfo));
});
this._tempTransmuxer.on(TransmuxingEvents.RECOMMEND_SEEKPOINT, (milliseconds) => {
if (this._transmuxer === this._tempTransmuxer && this._mediaElement && !this._config.accurateSeek) {
this._requestSetTime = true;
this._mediaElement.currentTime = milliseconds / 1000;
}
});
this._transmuxer.open()
}
this._tempTransmuxer.open();
unload () {
if (this._mediaElement) {
this._mediaElement.pause()
}
load() {
if (!this._mediaElement) {
throw new IllegalStateException('HTMLMediaElement must be attached before load()!');
}
if (this._transmuxer) {
throw new IllegalStateException('FlvPlayer.load() has been called, please call unload() first!');
}
if (this._hasPendingLoad) {
return;
}
if (this._msectl) {
this._msectl.seek(0)
}
if (this._transmuxer) {
this._transmuxer.close()
this._transmuxer.destroy()
this._transmuxer = null
}
}
if (this._config.deferLoadAfterSourceOpen && this._mseSourceOpened === false) {
this._hasPendingLoad = true;
return;
}
play () {
return this._mediaElement.play()
}
if (this._mediaElement.readyState > 0) {
this._requestSetTime = true;
// IE11 may throw InvalidStateError if readyState === 0
this._mediaElement.currentTime = 0;
}
pause () {
this._mediaElement.pause()
}
this._transmuxer = new Transmuxer(this._mediaDataSource, this._config);
get type () {
return this._type
}
this._transmuxer.on(TransmuxingEvents.INIT_SEGMENT, (type, is) => {
this._msectl.appendInitSegment(is);
});
this._transmuxer.on(TransmuxingEvents.MEDIA_SEGMENT, (type, ms) => {
this._msectl.appendMediaSegment(ms);
get buffered () {
return this._mediaElement.buffered
}
// lazyLoad check
if (this._config.lazyLoad && !this._config.isLive) {
let currentTime = this._mediaElement.currentTime;
if (ms.info.endDts >= (currentTime + this._config.lazyLoadMaxDuration) * 1000) {
if (this._progressChecker == null) {
Log.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
this._suspendTransmuxer();
}
}
}
});
this._transmuxer.on(TransmuxingEvents.LOADING_COMPLETE, () => {
this._msectl.endOfStream();
this._emitter.emit(PlayerEvents.LOADING_COMPLETE);
});
this._transmuxer.on(TransmuxingEvents.RECOVERED_EARLY_EOF, () => {
this._emitter.emit(PlayerEvents.RECOVERED_EARLY_EOF);
});
this._transmuxer.on(TransmuxingEvents.IO_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.NETWORK_ERROR, detail, info);
});
this._transmuxer.on(TransmuxingEvents.DEMUX_ERROR, (detail, info) => {
this._emitter.emit(PlayerEvents.ERROR, ErrorTypes.MEDIA_ERROR, detail, {code: -1, msg: info});
});
this._transmuxer.on(TransmuxingEvents.MEDIA_INFO, (mediaInfo) => {
this._mediaInfo = mediaInfo;
this._emitter.emit(PlayerEvents.MEDIA_INFO, Object.assign({}, mediaInfo));
});
this._transmuxer.on(TransmuxingEvents.STATISTICS_INFO, (statInfo) => {
this._statisticsInfo = this._fillStatisticsInfo(statInfo);
this._emitter.emit(PlayerEvents.STATISTICS_INFO, Object.assign({}, this._statisticsInfo));
});
this._transmuxer.on(TransmuxingEvents.RECOMMEND_SEEKPOINT, (milliseconds) => {
if (this._mediaElement && !this._config.accurateSeek) {
this._requestSetTime = true;
this._mediaElement.currentTime = milliseconds / 1000;
}
});
get duration () {
return this._mediaElement.duration
}
this._transmuxer.open();
}
get volume () {
return this._mediaElement.volume
}
unload() {
if (this._mediaElement) {
this._mediaElement.pause();
}
if (this._msectl) {
this._msectl.seek(0);
}
if (this._transmuxer) {
this._transmuxer.close();
this._transmuxer.destroy();
this._transmuxer = null;
}
}
set volume (value) {
this._mediaElement.volume = value
}
play() {
return this._mediaElement.play();
}
get muted () {
return this._mediaElement.muted
}
pause() {
this._mediaElement.pause();
}
set muted (muted) {
this._mediaElement.muted = muted
}
get type() {
return this._type;
get currentTime () {
if (this._mediaElement) {
return this._mediaElement.currentTime
}
return 0
}
get buffered() {
return this._mediaElement.buffered;
set currentTime (seconds) {
if (this._mediaElement) {
this._internalSeek(seconds)
} else {
this._pendingSeekTime = seconds
}
}
get duration() {
return this._mediaElement.duration;
}
get mediaInfo () {
return Object.assign({}, this._mediaInfo)
}
get volume() {
return this._mediaElement.volume;
get statisticsInfo () {
if (this._statisticsInfo == null) {
this._statisticsInfo = {}
}
this._statisticsInfo = this._fillStatisticsInfo(this._statisticsInfo)
return Object.assign({}, this._statisticsInfo)
}
set volume(value) {
this._mediaElement.volume = value;
}
_fillStatisticsInfo (statInfo) {
statInfo.playerType = this._type
get muted() {
return this._mediaElement.muted;
if (!(this._mediaElement instanceof window.HTMLVideoElement)) {
return statInfo
}
set muted(muted) {
this._mediaElement.muted = muted;
}
let hasQualityInfo = true
let decoded = 0
let dropped = 0
get currentTime() {
if (this._mediaElement) {
return this._mediaElement.currentTime;
}
return 0;
if (this._mediaElement.getVideoPlaybackQuality) {
let quality = this._mediaElement.getVideoPlaybackQuality()
decoded = quality.totalVideoFrames
dropped = quality.droppedVideoFrames
} else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
decoded = this._mediaElement.webkitDecodedFrameCount
dropped = this._mediaElement.webkitDroppedFrameCount
} else {
hasQualityInfo = false
}
set currentTime(seconds) {
if (this._mediaElement) {
this._internalSeek(seconds);
} else {
this._pendingSeekTime = seconds;
}
if (hasQualityInfo) {
statInfo.decodedFrames = decoded
statInfo.droppedFrames = dropped
}
get mediaInfo() {
return Object.assign({}, this._mediaInfo);
}
return statInfo
}
get statisticsInfo() {
if (this._statisticsInfo == null) {
this._statisticsInfo = {};
}
this._statisticsInfo = this._fillStatisticsInfo(this._statisticsInfo);
return Object.assign({}, this._statisticsInfo);
_onmseUpdateEnd () {
if (!this._config.lazyLoad || this._config.isLive) {
return
}
_fillStatisticsInfo(statInfo) {
statInfo.playerType = this._type;
let buffered = this._mediaElement.buffered
let currentTime = this._mediaElement.currentTime
let currentRangeStart = 0
let currentRangeEnd = 0
if (!(this._mediaElement instanceof HTMLVideoElement)) {
return statInfo;
}
let hasQualityInfo = true;
let decoded = 0;
let dropped = 0;
if (this._mediaElement.getVideoPlaybackQuality) {
let quality = this._mediaElement.getVideoPlaybackQuality();
decoded = quality.totalVideoFrames;
dropped = quality.droppedVideoFrames;
} else if (this._mediaElement.webkitDecodedFrameCount != undefined) {
decoded = this._mediaElement.webkitDecodedFrameCount;
dropped = this._mediaElement.webkitDroppedFrameCount;
} else {
hasQualityInfo = false;
}
if (hasQualityInfo) {
statInfo.decodedFrames = decoded;
statInfo.droppedFrames = dropped;
}
return statInfo;
for (let i = 0; i < buffered.length; i++) {
let start = buffered.start(i)
let end = buffered.end(i)
if (start <= currentTime && currentTime < end) {
currentRangeStart = start
currentRangeEnd = end
break
}
}
_onmseUpdateEnd() {
if (!this._config.lazyLoad || this._config.isLive) {
return;
}
let buffered = this._mediaElement.buffered;
let currentTime = this._mediaElement.currentTime;
let currentRangeStart = 0;
let currentRangeEnd = 0;
for (let i = 0; i < buffered.length; i++) {
let start = buffered.start(i);
let end = buffered.end(i);
if (start <= currentTime && currentTime < end) {
currentRangeStart = start;
currentRangeEnd = end;
break;
}
}
if (currentRangeEnd >= currentTime + this._config.lazyLoadMaxDuration && this._progressChecker == null) {
Log.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task');
this._suspendTransmuxer();
}
if (currentRangeEnd >= currentTime + this._config.lazyLoadMaxDuration && this._progressChecker == null) {
Log.v(this.TAG, 'Maximum buffering duration exceeded, suspend transmuxing task')
this._suspendTransmuxer()
}
}
_onmseBufferFull() {
Log.v(this.TAG, 'MSE SourceBuffer is full, suspend transmuxing task');
if (this._progressChecker == null) {
this._suspendTransmuxer();
}
_onmseBufferFull () {
Log.v(this.TAG, 'MSE SourceBuffer is full, suspend transmuxing task')
if (this._progressChecker == null) {
this._suspendTransmuxer()
}
}
_suspendTransmuxer() {
if (this._transmuxer) {
this._transmuxer.pause();
_suspendTransmuxer () {
if (this._transmuxer) {
this._transmuxer.pause()
if (this._progressChecker == null) {
this._progressChecker = window.setInterval(this._checkProgressAndResume.bind(this), 1000);
}
}
if (this._progressChecker == null) {
this._progressChecker = window.setInterval(this._checkProgressAndResume.bind(this), 1000)
}
}
}
_checkProgressAndResume() {
let currentTime = this._mediaElement.currentTime;
let buffered = this._mediaElement.buffered;
_checkProgressAndResume () {
let currentTime = this._mediaElement.currentTime
let buffered = this._mediaElement.buffered
let needResume = false;
let needResume = false
for (let i = 0; i < buffered.length; i++) {
let from = buffered.start(i);
let to = buffered.end(i);
if (currentTime >= from && currentTime < to) {
if (currentTime >= to - this._config.lazyLoadRecoverDuration) {
needResume = true;
}
break;
}
for (let i = 0; i < buffered.length; i++) {
let from = buffered.start(i)
let to = buffered.end(i)
if (currentTime >= from && currentTime < to) {
if (currentTime >= to - this._config.lazyLoadRecoverDuration) {
needResume = true
}
break
}
}
if (needResume) {
window.clearInterval(this._progressChecker);
this._progressChecker = null;
if (needResume) {
Log.v(this.TAG, 'Continue loading from paused position');
this._transmuxer.resume();
}
}
if (needResume) {
window.clearInterval(this._progressChecker)
this._progressChecker = null
if (needResume) {
Log.v(this.TAG, 'Continue loading from paused position')
this._transmuxer.resume()
}
}
}
_isTimepointBuffered(seconds) {
let buffered = this._mediaElement.buffered;
_isTimepointBuffered (seconds) {
let buffered = this._mediaElement.buffered
for (let i = 0; i < buffered.length; i++) {
let from = buffered.start(i);
let to = buffered.end(i);
if (seconds >= from && seconds < to) {
return true;
}
}
return false;
for (let i = 0; i < buffered.length; i++) {
let from = buffered.start(i)
let to = buffered.end(i)
if (seconds >= from && seconds < to) {
return true
}
}
return false
}
_internalSeek(seconds) {
let directSeek = this._isTimepointBuffered(seconds);
_internalSeek (seconds) {
let directSeek = this._isTimepointBuffered(seconds)
let directSeekBegin = false;
let directSeekBeginTime = 0;
let directSeekBegin = false
let directSeekBeginTime = 0
if (seconds < 1.0 && this._mediaElement.buffered.length > 0) {
let videoBeginTime = this._mediaElement.buffered.start(0);
if ((videoBeginTime < 1.0 && seconds < videoBeginTime) || Browser.safari) {
directSeekBegin = true;
// also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
directSeekBeginTime = Browser.safari ? 0.1 : videoBeginTime;
}
}
if (seconds < 1.0 && this._mediaElement.buffered.length > 0) {
let videoBeginTime = this._mediaElement.buffered.start(0)
if ((videoBeginTime < 1.0 && seconds < videoBeginTime) || Browser.safari) {
directSeekBegin = true
// also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
directSeekBeginTime = Browser.safari ? 0.1 : videoBeginTime
}
}
if (directSeekBegin) { // seek to video begin, set currentTime directly if beginPTS buffered
this._requestSetTime = true;
this._mediaElement.currentTime = directSeekBeginTime;
} else if (directSeek) { // buffered position
if (!this._alwaysSeekKeyframe) {
this._requestSetTime = true;
this._mediaElement.currentTime = seconds;
} else {
let idr = this._msectl.getNearestKeyframe(Math.floor(seconds * 1000));
this._requestSetTime = true;
if (idr != null) {
this._mediaElement.currentTime = idr.dts / 1000;
} else {
this._mediaElement.currentTime = seconds;
}
}
if (this._progressChecker != null) {
this._checkProgressAndResume();
}
if (directSeekBegin) { // seek to video begin, set currentTime directly if beginPTS buffered
this._requestSetTime = true
this._mediaElement.currentTime = directSeekBeginTime
} else if (directSeek) { // buffered position
if (!this._alwaysSeekKeyframe) {
this._requestSetTime = true
this._mediaElement.currentTime = seconds
} else {
let idr = this._msectl.getNearestKeyframe(Math.floor(seconds * 1000))
this._requestSetTime = true
if (idr != null) {
this._mediaElement.currentTime = idr.dts / 1000
} else {
if (this._progressChecker != null) {
window.clearInterval(this._progressChecker);
this._progressChecker = null;
}
this._msectl.seek(seconds);
this._transmuxer.seek(Math.floor(seconds * 1000)); // in milliseconds
// no need to set mediaElement.currentTime if non-accurateSeek,
// just wait for the recommend_seekpoint callback
if (this._config.accurateSeek) {
this._requestSetTime = true;
this._mediaElement.currentTime = seconds;
}
this._mediaElement.currentTime = seconds
}
}
if (this._progressChecker != null) {
this._checkProgressAndResume()
}
} else {
if (this._progressChecker != null) {
window.clearInterval(this._progressChecker)
this._progressChecker = null
}
this._msectl.seek(seconds)
this._transmuxer.seek(Math.floor(seconds * 1000)) // in milliseconds
// no need to set mediaElement.currentTime if non-accurateSeek,
// just wait for the recommend_seekpoint callback
if (this._config.accurateSeek) {
this._requestSetTime = true
this._mediaElement.currentTime = seconds
}
}
}
_checkAndApplyUnbufferedSeekpoint() {
if (this._seekpointRecord) {
if (this._seekpointRecord.recordTime <= this._now() - 100) {
let target = this._mediaElement.currentTime;
this._seekpointRecord = null;
if (!this._isTimepointBuffered(target)) {
if (this._progressChecker != null) {
window.clearTimeout(this._progressChecker);
this._progressChecker = null;
}
// .currentTime is consists with .buffered timestamp
// Chrome/Edge use DTS, while FireFox/Safari use PTS
this._msectl.seek(target);
this._transmuxer.seek(Math.floor(target * 1000));
// set currentTime if accurateSeek, or wait for recommend_seekpoint callback
if (this._config.accurateSeek) {
this._requestSetTime = true;
this._mediaElement.currentTime = target;
}
}
} else {
window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
}
_checkAndApplyUnbufferedSeekpoint () {
if (this._seekpointRecord) {
if (this._seekpointRecord.recordTime <= this._now() - 100) {
let target = this._mediaElement.currentTime
this._seekpointRecord = null
if (!this._isTimepointBuffered(target)) {
if (this._progressChecker != null) {
window.clearTimeout(this._progressChecker)
this._progressChecker = null
}
// .currentTime is consists with .buffered timestamp
// Chrome/Edge use DTS, while FireFox/Safari use PTS
this._msectl.seek(target)
this._transmuxer.seek(Math.floor(target * 1000))
// set currentTime if accurateSeek, or wait for recommend_seekpoint callback
if (this._config.accurateSeek) {
this._requestSetTime = true
this._mediaElement.currentTime = target
}
}
} else {
window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50)
}
}
}
_checkAndResumeStuckPlayback(stalled) {
let media = this._mediaElement;
if (stalled || !this._receivedCanPlay || media.readyState < 2) { // HAVE_CURRENT_DATA
let buffered = media.buffered;
if (buffered.length > 0 && media.currentTime < buffered.start(0)) {
Log.w(this.TAG, `Playback seems stuck at ${media.currentTime}, seek to ${buffered.start(0)}`);
this._requestSetTime = true;
this._mediaElement.currentTime = buffered.start(0);
this._mediaElement.removeEventListener('progress', this.e.onvProgress);
}
} else {
// Playback didn't stuck, remove progress event listener
this._mediaElement.removeEventListener('progress', this.e.onvProgress);
}
_checkAndResumeStuckPlayback (stalled) {
let media = this._mediaElement
if (stalled || !this._receivedCanPlay || media.readyState < 2) { // HAVE_CURRENT_DATA
let buffered = media.buffered
if (buffered.length > 0 && media.currentTime < buffered.start(0)) {
Log.w(this.TAG, `Playback seems stuck at ${media.currentTime}, seek to ${buffered.start(0)}`)
this._requestSetTime = true
this._mediaElement.currentTime = buffered.start(0)
this._mediaElement.removeEventListener('progress', this.e.onvProgress)
}
} else {
// Playback didn't stuck, remove progress event listener
this._mediaElement.removeEventListener('progress', this.e.onvProgress)
}
}
_onvLoadedMetadata(e) {
if (this._pendingSeekTime != null) {
this._mediaElement.currentTime = this._pendingSeekTime;
this._pendingSeekTime = null;
}
_onvLoadedMetadata (e) {
if (this._pendingSeekTime != null) {
this._mediaElement.currentTime = this._pendingSeekTime
this._pendingSeekTime = null
}
}
_onvSeeking(e) { // handle seeking request from browser's progress bar
let target = this._mediaElement.currentTime;
let buffered = this._mediaElement.buffered;
_onvSeeking (e) { // handle seeking request from browser's progress bar
let target = this._mediaElement.currentTime
let buffered = this._mediaElement.buffered
if (this._requestSetTime) {
this._requestSetTime = false;
return;
}
if (this._requestSetTime) {
this._requestSetTime = false
return
}
if (target < 1.0 && buffered.length > 0) {
// seek to video begin, set currentTime directly if beginPTS buffered
let videoBeginTime = buffered.start(0);
if ((videoBeginTime < 1.0 && target < videoBeginTime) || Browser.safari) {
this._requestSetTime = true;
// also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
this._mediaElement.currentTime = Browser.safari ? 0.1 : videoBeginTime;
return;
}
}
if (target < 1.0 && buffered.length > 0) {
// seek to video begin, set currentTime directly if beginPTS buffered
let videoBeginTime = buffered.start(0)
if ((videoBeginTime < 1.0 && target < videoBeginTime) || Browser.safari) {
this._requestSetTime = true
// also workaround for Safari: Seek to 0 may cause video stuck, use 0.1 to avoid
this._mediaElement.currentTime = Browser.safari ? 0.1 : videoBeginTime
return
}
}
if (this._isTimepointBuffered(target)) {
if (this._alwaysSeekKeyframe) {
let idr = this._msectl.getNearestKeyframe(Math.floor(target * 1000));
if (idr != null) {
this._requestSetTime = true;
this._mediaElement.currentTime = idr.dts / 1000;
}
}
if (this._progressChecker != null) {
this._checkProgressAndResume();
}
return;
if (this._isTimepointBuffered(target)) {
if (this._alwaysSeekKeyframe) {
let idr = this._msectl.getNearestKeyframe(Math.floor(target * 1000))
if (idr != null) {
this._requestSetTime = true
this._mediaElement.currentTime = idr.dts / 1000
}
this._seekpointRecord = {
seekPoint: target,
recordTime: this._now()
};
window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50);
}
if (this._progressChecker != null) {
this._checkProgressAndResume()
}
return
}
_onvCanPlay(e) {
this._receivedCanPlay = true;
this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
this._seekpointRecord = {
seekPoint: target,
recordTime: this._now()
}
window.setTimeout(this._checkAndApplyUnbufferedSeekpoint.bind(this), 50)
}
_onvStalled(e) {
this._checkAndResumeStuckPlayback(true);
}
_onvCanPlay (e) {
this._receivedCanPlay = true
this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay)
}
_onvProgress(e) {
this._checkAndResumeStuckPlayback();
}
_onvStalled (e) {
this._checkAndResumeStuckPlayback(true)
}
get isDefinitionDataReady() {
const minSegmentLen = this._config.isLive ? 1 : 2;
return Object.keys(this._tempPendingSegments).every((key) => this._tempPendingSegments[key].length >= minSegmentLen);
}
_onvProgress (e) {
this._checkAndResumeStuckPlayback()
}
get isDefinitionDataReady () {
const minSegmentLen = 10
return Object.keys(this._tempPendingSegments).every((key) => this._tempPendingSegments[key].length >= minSegmentLen)
}
}
export default FlvPlayer;
export default FlvPlayer

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc