Как изменить битрейт в зависимости от скорости интернета в плеере JW
Возможно ли это с помощью этого кода: jwplayer(). GetQualityLevels()
1 ответ
Исходя из вашего вопроса, я предполагаю, что вы не используете HLS или DASH, но вместо этого у вас есть несколько MP4, которые были закодированы с различными битрейтами или разрешениями. MP4 необходимо правильно кодировать для поддержки прогрессивной загрузки, а http-сервер должен поддерживать заголовки диапазона байтов. Можно отслеживать буфер jwplayer, а когда он становится слишком низким, вы можете переключиться на источник более низкого качества. Мы делаем это как http://www.scormfly.com/. Вот некоторый машинописный код, который поможет вам начать.
import * as _ from 'lodash'
import Controls, { StreamingMode } from '../controls'
const controls = new Controls()
export default class ProgressiveDownloadProvider {
private positionBeforeQualityChange = 0
private isSeeking: boolean
private jwplayer: JWPlayer
constructor(jwplayer: JWPlayer) {
jwplayer.on('levels', this.setToBestFitQuality)
jwplayer.on('levelsChanged', this.onQualityChange)
jwplayer.on('time', this.tick)
this.jwplayer = jwplayer
}
public tick(args: TimeParam) {
if (this.isQualityTooHigh(args.position)) {
this.reduceQualityLevel()
}
}
public onResize() {
// don't change the quality unless the the video is playing
// because changing the quality will start playing the video
if (this.jwplayer.getState().toUpperCase() === 'PLAYING') {
this.setToBestFitQuality()
}
}
private isQualityTooHigh(currentPosition: number): boolean {
if (this.isSeeking) { return false }
if (currentPosition < this.positionBeforeQualityChange + 1) { return false }
const videoElement = $('video')[0]
const bufferPositionInSeconds = videoElement ?
(videoElement as any).buffered.end((videoElement as any).buffered.length - 1) :
this.jwplayer.getBuffer() / 100.0 * controls.getDuration()
const bufferAlmostComplete = bufferPositionInSeconds > controls.getDuration() - 10
if (bufferAlmostComplete) { return false }
const bufferRunningLow = bufferPositionInSeconds - currentPosition < 0.5
return bufferRunningLow
}
private reduceQualityLevel() {
// qualityLevels are indexed 0-best to 5-worst quality
const qualityLevels = this.jwplayer.getQualityLevels()
const indexOfWorstQuality = qualityLevels.length - 1
const indexOfCurrentQuality = this.jwplayer.getCurrentQuality()
if (indexOfCurrentQuality === indexOfWorstQuality) { return }
// tslint:disable-next-line:no-console
console.log('reducing quality from '
+ qualityLevels[indexOfCurrentQuality].label + ' to '
+ qualityLevels[indexOfCurrentQuality + 1].label + ' due to buffering')
this.jwplayer.setCurrentQuality(indexOfCurrentQuality + 1)
}
// detect viewport height and use the best fitting source
private setToBestFitQuality() {
if (controls.getStreamingMode() === StreamingMode.YouTube) { return } // don't adjust youtube videos
if (typeof this.jwplayer.getQualityLevels() === 'undefined') { return } // not ready yet
if (this.jwplayer.getQualityLevels().length === 0) { return } // nothing to do
if (this.jwplayer.getCurrentQuality() === -1) { return } // this can happen onComplete
const newHeight = $('#jwPlayer').height()
const currentQuality = this.jwplayer.getQualityLevels()[this.jwplayer.getCurrentQuality()].label // eg 720p HD
let optimalQuality: string
const heights = _.map(this.jwplayer.getQualityLevels(), (item) => item.label.replace('p', ''))
for (const height of heights) {
const tooBig = height > newHeight
if (tooBig) {
break
}
optimalQuality = height + 'p'
}
if (optimalQuality !== this.jwplayer.getQualityLevels()[this.jwplayer.getCurrentQuality()].label) {
// tslint:disable-next-line:no-console
console.log('Switching quality to '
+ optimalQuality + ' because window will fit up to '
+ $(window).height() + 'p')
// find desired quality level and use it
const levels = this.jwplayer.getQualityLevels()
for (let j = 0; j < levels.length; j++) {
if (levels[j].label === optimalQuality) {
this.jwplayer.setCurrentQuality(j)
}
}
}
}
// preserve playback position
private onQualityChange() {
this.positionBeforeQualityChange = this.jwplayer.getPosition()
setTimeout(() => {
controls.seek(this.positionBeforeQualityChange)
}, 500)
}
}