如何在JW播放器中基于互联网速度改变比特率

时间:2017-11-21 08:08:37

标签: javascript jwplayer wowza jwplayer6

使用此代码是否可行: jwplayer()。getQualityLevels()

1 个答案:

答案 0 :(得分:0)

根据您的问题,我认为您没有使用HLS或DASH,而是您有几个MP4以不同的比特率或分辨率编码。 MP4需要正确编码以支持渐进式下载,http服务器需要支持字节范围的标头。可以监视jwplayer的缓冲区,当它变得太低时,您可以切换到质量较低的源。我们这样做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)
  }

}