From 00ebda749e588f0eb82b3c0760576c5612b2b1ce Mon Sep 17 00:00:00 2001 From: Tim Fischbach Date: Tue, 2 Mar 2021 09:38:01 +0100 Subject: [PATCH] Add usePlayerObjectFit option Only consider `object-fit` CSS property when selecting playlists based on play size when `usePlayerObjectFit` option is `true` to make new behavior an opt-in. --- README.md | 10 ++++++++++ src/playlist-selectors.js | 14 ++++++++++---- src/videojs-http-streaming.js | 3 +++ test/configuration.test.js | 5 +++++ test/playlist-selectors.test.js | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 171221173..404abd706 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ Video.js Compatibility: 6.0, 7.0 - [enableLowInitialPlaylist](#enablelowinitialplaylist) - [limitRenditionByPlayerDimensions](#limitrenditionbyplayerdimensions) - [useDevicePixelRatio](#usedevicepixelratio) + - [usePlayerObjectFit](#useplayerobjectfit) - [smoothQualityChange](#smoothqualitychange) - [allowSeeksWithinUnsafeLiveWindow](#allowseekswithinunsafelivewindow) - [customTagParsers](#customtagparsers) @@ -401,6 +402,15 @@ This setting is `true` by default. If true, this will take the device pixel ratio into account when doing rendition switching. This means that if you have a player with the width of `540px` in a high density display with a device pixel ratio of 2, a rendition of `1080p` will be allowed. This setting is `false` by default. +##### usePlayerObjectFit +* Type: `boolean` +* can be used as an initialization option. + +If true, the video element's `object-fit` CSS property will be taken +into account when doing rendition switching. This ensures that a +suitable rendition is selected for videos that are scaled up to cover +the media element. This setting is `false` by default. + ##### smoothQualityChange * Type: `boolean` * can be used as a source option diff --git a/src/playlist-selectors.js b/src/playlist-selectors.js index 6760b5412..490b6ed0f 100644 --- a/src/playlist-selectors.js +++ b/src/playlist-selectors.js @@ -144,9 +144,12 @@ export const comparePlaylistResolution = function(left, right) { * @param {number} settings.playerHeight * Current height of the player element (should account for the device pixel ratio) * @param {number} settings.playerObjectFit - * Current value of the video element's object-fit CSS property. Allows taking into - * account that the video might be scaled up to cover the media element when selecting - * media playlists based on player size. + * Current value of the video element's object-fit CSS property. + * @param {boolean} settings.usePlayerObjectFit + * True if the video element's object-fit CSS property shall be taken into account + * when selecting media playlists based on player size, false otherwise. + * Ensures a suitable renditions is selected for videos that are scaled up to cover + * the media element. * @param {boolean} settings.limitRenditionByPlayerDimensions * True if the player width and height should be used during the selection, false otherwise * @return {Playlist} the highest bitrate playlist less than the @@ -160,6 +163,7 @@ export const simpleSelector = function(settings) { playerWidth, playerHeight, playerObjectFit, + usePlayerObjectFit, limitRenditionByPlayerDimensions } = settings; @@ -267,7 +271,7 @@ export const simpleSelector = function(settings) { // if there is no match of exact resolution if (!resolutionBestRep) { resolutionPlusOneList = haveResolution.filter((rep) => { - if (playerObjectFit === 'cover') { + if (playerObjectFit === 'cover' && usePlayerObjectFit) { // video will be scaled up to cover the player. We need to // make sure rendition is at least as wide and as high as the // player. @@ -340,6 +344,7 @@ export const lastBandwidthSelector = function() { playerWidth: parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10) * pixelRatio, playerHeight: parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10) * pixelRatio, playerObjectFit: safeGetComputedStyle(this.tech_.el(), 'objectFit'), + usePlayerObjectFit: this.usePlayerObjectFit, limitRenditionByPlayerDimensions: this.limitRenditionByPlayerDimensions }); }; @@ -379,6 +384,7 @@ export const movingAverageBandwidthSelector = function(decay) { playerWidth: parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10) * pixelRatio, playerHeight: parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10) * pixelRatio, playerObjectFit: safeGetComputedStyle(this.tech_.el(), 'objectFit'), + usePlayerObjectFit: this.usePlayerObjectFit, limitRenditionByPlayerDimensions: this.limitRenditionByPlayerDimensions }); }; diff --git a/src/videojs-http-streaming.js b/src/videojs-http-streaming.js index fa656f1a4..490f47f30 100644 --- a/src/videojs-http-streaming.js +++ b/src/videojs-http-streaming.js @@ -608,6 +608,7 @@ class VhsHandler extends Component { this.options_.handleManifestRedirects = this.options_.handleManifestRedirects === false ? false : true; this.options_.limitRenditionByPlayerDimensions = this.options_.limitRenditionByPlayerDimensions === false ? false : true; this.options_.useDevicePixelRatio = this.options_.useDevicePixelRatio || false; + this.options_.usePlayerObjectFit = this.options_.usePlayerObjectFit || false; this.options_.smoothQualityChange = this.options_.smoothQualityChange || false; this.options_.useBandwidthFromLocalStorage = typeof this.source_.useBandwidthFromLocalStorage !== 'undefined' ? @@ -654,6 +655,7 @@ class VhsHandler extends Component { [ 'withCredentials', 'useDevicePixelRatio', + 'usePlayerObjectFit', 'limitRenditionByPlayerDimensions', 'bandwidth', 'smoothQualityChange', @@ -674,6 +676,7 @@ class VhsHandler extends Component { this.limitRenditionByPlayerDimensions = this.options_.limitRenditionByPlayerDimensions; this.useDevicePixelRatio = this.options_.useDevicePixelRatio; + this.usePlayerObjectFit = this.options_.usePlayerObjectFit; } /** * called when player.src gets called, handle a new source diff --git a/test/configuration.test.js b/test/configuration.test.js index 7087e9516..db9dea226 100644 --- a/test/configuration.test.js +++ b/test/configuration.test.js @@ -31,6 +31,11 @@ const options = [{ default: false, test: true, alt: false +}, { + name: 'usePlayerObjectFit', + default: false, + test: true, + alt: false }, { name: 'bandwidth', default: 4194304, diff --git a/test/playlist-selectors.test.js b/test/playlist-selectors.test.js index 9f7d7ecc8..ecda46c5c 100644 --- a/test/playlist-selectors.test.js +++ b/test/playlist-selectors.test.js @@ -210,6 +210,23 @@ test('simpleSelector limits using resolution information when it exists', functi assert.equal(selectedPlaylist, master.playlists[3], 'selected the playlist with the lowest bandwidth and a resolution that exceeds player size in at least one dimension'); }); +test('simpleSelector does not take object fit into account by default', function(assert) { + const master = this.vhs.playlists.master; + + master.playlists = trickyPlaylists; + + const selectedPlaylist = simpleSelector({ + master, + bandwidth: 4194304, + playerWidth: 444, + playerHeight: 500, + playerObjectFit: 'cover', + limitRenditionByPlayerDimensions: true + }); + + assert.equal(selectedPlaylist, master.playlists[3], 'selected the playlist with the lowest bandwidth and a resolution that exceeds player size in at least one dimension'); +}); + test('simpleSelector can take object fit into account', function(assert) { const master = this.vhs.playlists.master; @@ -221,6 +238,7 @@ test('simpleSelector can take object fit into account', function(assert) { playerWidth: 444, playerHeight: 500, playerObjectFit: 'cover', + usePlayerObjectFit: true, limitRenditionByPlayerDimensions: true });