videojs / videojs-contrib-quality-levels

Other
157 stars 51 forks source link

feature request: change to a specific level helper method. [was: The simplest of questions: how do you change the quality?] #150

Open Florinstruct opened 7 months ago

Florinstruct commented 7 months ago

Description

I can't for the life of me find any info on how to actually change the quality. The following part from your documentation makes me think this is outside the scope of this plugin?!

When your playback plugin changes the selected quality for playback...

Now, your documentation also says we need videojs/http-streaming and they write:

See the videojs-contrib-quality-levels project page for more information on how to use the api.

So, which is it now? Does this plugin provide an API or does videojs itself?

Steps

I'm using this snippet from your page:

qualityLevels.selectedIndex_ = 0;
qualityLevels.trigger({ type: 'change', selectedIndex: 0 });

But this does nothing. Apparently, it's really just there to "update the QualityLevelList.selectedIndex_" - for whatever reason I would want to / have to do that myself.

If I am misunderstanding the README, there seem to be others. Maybe the documentation is just not clear?

metal450 commented 4 months ago

Did you ever figure this out? I can't get it working either. Seems like incredibly unclear docs to me.

kennethstarkrl commented 4 months ago
const player = (playerRef.current = videojs(videoElement, options, () => {
    player.on('loadedmetadata', () => {
      const qualityLevels = player.qualityLevels();
      qualityLevels.on('change', function() {
        console.log('Quality Level changed!');
        console.log('New level:', qualityLevels[qualityLevels.selectedIndex]);
        const currentTime = player.currentTime();
        player.src(options.sources[qualityLevels.selectedIndex]); //<--- change the source
        player.currentTime(currentTime); // <-- set the new source to the previous source current seek position
        player.play();
      });
    });
}));
pac96 commented 1 month ago

I am having the same issue. The docs seem unclear to me, and the recommendation to use options.sources doesn't work for me because I only have 1 HLS video source.

gkatsev commented 1 month ago

Thanks for everyone's patience. It turns out that our documentation is misleading and that triggering change isn't how you change renditions. The docs were misleading enough that I thought the above was correct until I went to double-check, which is one of the reasons I haven't replied previously.

To actually change the quality level, you want to set enabled = true on the levels you want to continue playing and enabled = false on those you don't. So, if you want a single rendition playing, you'd want to enable only that one rendition and have the rest be set to false.

For example, to enable the 1080p rendition, you could do the following:

Array.from(player.qualityLevels()).forEach(l => l.enabled = l.height === 1080) 

See the handleClick method in our quality menu plugin for a detailed example: https://github.com/videojs/videojs-contrib-quality-menu/blob/main/src/quality-menu-item.js#L103-L127

When trying it out locally, I noticed some issues, and the quality menu method has a workaround for the issue I was running into https://github.com/videojs/videojs-contrib-quality-menu/blob/356341602d796a93cd1e305c1c8136b776a602b4/src/quality-menu-item.js#L110-L112, which leads me to believe that this plugin probably needs to have a method for selecting a single rendition (and for switching back to full auto switching).

The selectedIndex and the change event in more targeted and folks that are integrating this library into another component like a quality menu. Though, if you do change the rendition, it's nice to trigger the change event in case another plugin or something wants to know whether the quality level has changed.

Finally, if you want to never allow a rendition to be played, you can remove it from the list via qualityLevel.removeQualityLevel(ql). So, if you want to disallow HD playback, you could remove all the levels with a height of 720p and higher.

gkatsev commented 1 month ago

Also, I updated the issue title to a feature request for the new helper method, but hopefully, my comment here helps folks until we get the docs updated (and until we get the new helper method)

bezumkin commented 1 month ago

I just invented a super stupid method:

const myQuality = 720

player.on('loadedmetadata', () => {
  const qualityLevels = player.qualityLevels()
  const idx = qualityLevels.levels_.findIndex((i) => i.height === myQuality)
  if (idx > -1) {
    const items = [...document.querySelectorAll('.vjs-quality-menu-wrapper .vjs-menu-item')].reverse()
    if (items && items[idx + 1]) {
      items[idx + 1].click()
    }
  }
})

Yes, I'm just clicking on menu item and it work for me.