2015-12-16 00:30:14 -05:00
|
|
|
/*
|
|
|
|
* FPS Controller
|
|
|
|
*/
|
|
|
|
|
|
|
|
import Event from '../events';
|
2016-04-16 12:51:35 -04:00
|
|
|
import EventHandler from '../event-handler';
|
2015-12-16 00:30:14 -05:00
|
|
|
import {logger} from '../utils/logger';
|
|
|
|
|
2016-04-16 12:51:35 -04:00
|
|
|
class FPSController extends EventHandler{
|
2015-12-16 00:30:14 -05:00
|
|
|
|
|
|
|
constructor(hls) {
|
2016-04-16 12:51:35 -04:00
|
|
|
super(hls, Event.MEDIA_ATTACHING);
|
2015-12-16 00:30:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {
|
|
|
|
if (this.timer) {
|
2016-04-16 12:51:35 -04:00
|
|
|
clearInterval(this.timer);
|
2015-12-16 00:30:14 -05:00
|
|
|
}
|
2016-04-16 12:51:35 -04:00
|
|
|
this.isVideoPlaybackQualityAvailable = false;
|
2015-12-16 00:30:14 -05:00
|
|
|
}
|
2016-04-16 12:51:35 -04:00
|
|
|
|
|
|
|
onMediaAttaching(data) {
|
|
|
|
if (this.hls.config.capLevelOnFPSDrop) {
|
|
|
|
this.video = data.media instanceof HTMLVideoElement ? data.media : null;
|
|
|
|
if (typeof this.video.getVideoPlaybackQuality === 'function') {
|
|
|
|
this.isVideoPlaybackQualityAvailable = true;
|
|
|
|
}
|
|
|
|
clearInterval(this.timer);
|
|
|
|
this.timer = setInterval(this.checkFPSInterval.bind(this), this.hls.config.fpsDroppedMonitoringPeriod);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
checkFPS(video, decodedFrames, droppedFrames) {
|
|
|
|
let currentTime = performance.now();
|
|
|
|
if (decodedFrames) {
|
|
|
|
if (this.lastTime) {
|
|
|
|
let currentPeriod = currentTime - this.lastTime,
|
|
|
|
currentDropped = droppedFrames - this.lastDroppedFrames,
|
|
|
|
currentDecoded = decodedFrames - this.lastDecodedFrames,
|
|
|
|
droppedFPS = 1000 * currentDropped / currentPeriod;
|
|
|
|
this.hls.trigger(Event.FPS_DROP, {currentDropped: currentDropped, currentDecoded: currentDecoded, totalDroppedFrames: droppedFrames});
|
|
|
|
if (droppedFPS > 0) {
|
|
|
|
//logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
|
|
|
if (currentDropped > this.hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
|
|
|
|
let currentLevel = this.hls.currentLevel;
|
|
|
|
logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
|
|
|
if (currentLevel > 0 && (this.hls.autoLevelCapping === -1 || this.hls.autoLevelCapping >= currentLevel)) {
|
|
|
|
currentLevel = currentLevel - 1;
|
|
|
|
this.hls.trigger(Event.FPS_DROP_LEVEL_CAPPING, {level: currentLevel, droppedLevel: this.hls.currentLevel});
|
|
|
|
this.hls.autoLevelCapping = currentLevel;
|
|
|
|
this.hls.streamController.nextLevelSwitch();
|
2015-12-16 00:30:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-04-16 12:51:35 -04:00
|
|
|
this.lastTime = currentTime;
|
|
|
|
this.lastDroppedFrames = droppedFrames;
|
|
|
|
this.lastDecodedFrames = decodedFrames;
|
2015-12-16 00:30:14 -05:00
|
|
|
}
|
|
|
|
}
|
2016-04-16 12:51:35 -04:00
|
|
|
|
|
|
|
checkFPSInterval() {
|
|
|
|
if (this.video) {
|
|
|
|
if (this.isVideoPlaybackQualityAvailable) {
|
|
|
|
let videoPlaybackQuality = this.video.getVideoPlaybackQuality();
|
|
|
|
this.checkFPS(this.video, videoPlaybackQuality.totalVideoFrames, videoPlaybackQuality.droppedVideoFrames);
|
|
|
|
} else {
|
|
|
|
this.checkFPS(this.video, this.video.webkitDecodedFrameCount, this.video.webkitDroppedFrameCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-16 00:30:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
export default FPSController;
|
|
|
|
|