Как изменить битрейт в зависимости от скорости интернета в плеере 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)
  }

}
Другие вопросы по тегам