Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add maxVideoBufferSize option to limit the amount of video data (in kilobytes?) the RxPlayer will push on low-end devices #1041

Merged
merged 13 commits into from
Mar 17, 2022
Merged
61 changes: 61 additions & 0 deletions demo/full/scripts/components/Options/BufferOptions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import DEFAULT_VALUES from "../../lib/defaultOptionsValues";
*/
function BufferOptions({
wantedBufferAhead,
maxVideoBufferSize,
maxBufferAhead,
maxBufferBehind,
onWantedBufferAheadInput,
onMaxVideoBufferSizeInput,
onMaxBufferAheadInput,
onMaxBufferBehindInput,
}) {
Expand All @@ -24,6 +26,10 @@ function BufferOptions({
maxBufferBehind !== Infinity
);

const [isMaxVideoBufferSizeLimited, setMaxVideoBufferSizeLimit] = useState(
maxVideoBufferSize !== Infinity
);

const onChangeLimitMaxBufferAHead = (evt) => {
const isNotLimited = getCheckBoxValue(evt.target);
if (isNotLimited) {
Expand All @@ -46,6 +52,17 @@ function BufferOptions({
}
};

const onChangeLimitMaxVideoBufferSize = (evt) => {
const isNotLimited = getCheckBoxValue(evt.target);
if (isNotLimited){
setMaxVideoBufferSizeLimit(false);
onMaxVideoBufferSizeInput(Infinity)
} else {
setMaxVideoBufferSizeLimit(true);
onMaxVideoBufferSizeInput(DEFAULT_VALUES.maxVideoBufferSize)
}
}

return (
<Fragment>
<li>
Expand Down Expand Up @@ -80,6 +97,50 @@ function BufferOptions({
</span>
</div>
</li>
<li>
<div className="playerOptionInput">
<label htmlFor="maxVideoBufferSize"> Max Video Buffer Size</label>
<span className="wrapperInputWithResetBtn">
<input
type="text"
step="10"
aria-label="maxVideoBufferSize option"
name="maxVideoBufferSize"
id="maxVideoBufferSize"
placeholder="Number"
onChange={(evt) => onMaxVideoBufferSizeInput(evt.target.value)}
value={maxVideoBufferSize}
disabled={isMaxVideoBufferSizeLimited === false}
className="optionInput"
/>
<Button
className={
parseFloat(maxVideoBufferSize) ===
DEFAULT_VALUES.maxVideoBufferSize
? "resetBtn disabledResetBtn"
: "resetBtn"
}
ariaLabel="Reset option to default value"
title="Reset option to default value"
onClick={() => {
setMaxVideoBufferSizeLimit(DEFAULT_VALUES.maxVideoBufferSize !==
Infinity);
onMaxVideoBufferSizeInput(DEFAULT_VALUES.maxVideoBufferSize);
}}
value={String.fromCharCode(0xf021)}
/>
</span>
</div>
<Checkbox
className="playerOptionsCheckBox"
ariaLabel="Do not limit maxVideoBufferSize option"
name="maxVideoBufferSizeLimit"
checked={isMaxVideoBufferSizeLimited === false}
onChange={onChangeLimitMaxVideoBufferSize}
>
Do not limit
</Checkbox>
</li>
<li>
<div className="playerOptionInput">
<label htmlFor="maxBufferAhead">Max Buffer Ahead</label>
Expand Down
8 changes: 8 additions & 0 deletions demo/full/scripts/controllers/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Settings extends React.Component {
maxVideoBr,
maxAudioBr,
wantedBufferAhead,
maxVideoBufferSize,
maxBufferAhead,
maxBufferBehind,
limitVideoWidth,
Expand All @@ -53,6 +54,7 @@ class Settings extends React.Component {
maxVideoBitrate: parseFloat(maxVideoBr),
maxAudioBitrate: parseFloat(maxAudioBr),
wantedBufferAhead: parseFloat(wantedBufferAhead),
maxVideoBufferSize: parseFloat(maxVideoBufferSize),
maxBufferAhead: parseFloat(maxBufferAhead),
maxBufferBehind: parseFloat(maxBufferBehind),
limitVideoWidth,
Expand Down Expand Up @@ -129,6 +131,9 @@ class Settings extends React.Component {

onWantedBufferAheadInput = (value) =>
this.setState({ wantedBufferAhead: value });

onMaxVideoBufferSizeInput = (value) =>
this.setState({ maxVideoBufferSize: value});

onMaxBufferBehindInput = (value) =>
this.setState({ maxBufferBehind: value });
Expand Down Expand Up @@ -156,6 +161,7 @@ class Settings extends React.Component {
audioTrackSwitchingMode,
onCodecSwitch,
wantedBufferAhead,
maxVideoBufferSize,
maxBufferAhead,
maxBufferBehind,
} = this.state;
Expand Down Expand Up @@ -232,11 +238,13 @@ class Settings extends React.Component {
<Option title="Buffer Options">
<BufferOptions
wantedBufferAhead={wantedBufferAhead}
maxVideoBufferSize={maxVideoBufferSize}
maxBufferAhead={maxBufferAhead}
maxBufferBehind={maxBufferBehind}
onWantedBufferAheadInput={this.onWantedBufferAheadInput}
onMaxBufferAheadInput={this.onMaxBufferAheadInput}
onMaxBufferBehindInput={this.onMaxBufferBehindInput}
onMaxVideoBufferSizeInput={this.onMaxVideoBufferSizeInput}
/>
</Option>
</div>
Expand Down
3 changes: 2 additions & 1 deletion demo/full/scripts/lib/defaultOptionsValues.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ const defaultOptionsValues = {
audioTrackSwitchingMode: "direct",
onCodecSwitch: "continue",
wantedBufferAhead: 30,
maxVideoBufferSize: Infinity,
maxBufferAhead: Infinity,
maxBufferBehind: Infinity,
};

export default defaultOptionsValues;
export default defaultOptionsValues;
61 changes: 34 additions & 27 deletions doc/api/Buffer_Control/.docConfig.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
{
"pages": [
{
"path": "./setWantedBufferAhead.md",
"displayName": "setWantedBufferAhead"
},
{
"path": "./getWantedBufferAhead.md",
"displayName": "getWantedBufferAhead"
},
{
"path": "./setMaxBufferBehind.md",
"displayName": "setMaxBufferBehind"
},
{
"path": "./getMaxBufferBehind.md",
"displayName": "getMaxBufferBehind"
},
{
"path": "./setMaxBufferAhead.md",
"displayName": "setMaxBufferAhead"
},
{
"path": "./getMaxBufferAhead.md",
"displayName": "getMaxBufferAhead"
}
]
}
"pages": [{
"path": "./setWantedBufferAhead.md",
"displayName": "setWantedBufferAhead"
},
{
"path": "./getWantedBufferAhead.md",
"displayName": "getWantedBufferAhead"
},
{
"path": "./setMaxBufferBehind.md",
"displayName": "setMaxBufferBehind"
},
{
"path": "./getMaxBufferBehind.md",
"displayName": "getMaxBufferBehind"
},
{
"path": "./setMaxBufferAhead.md",
"displayName": "setMaxBufferAhead"
},
{
"path": "./getMaxBufferAhead.md",
"displayName": "getMaxBufferAhead"
},
{
"path": "./getMaxVideoBufferSize.md",
"displayName": "getMaxVideoBufferSize"
},
{
"path": "./setMaxVideoBufferSize.md",
"displayName": "setMaxVideoBufferSize"
}
peaBerberian marked this conversation as resolved.
Show resolved Hide resolved
]
}
19 changes: 19 additions & 0 deletions doc/api/Buffer_Control/getMaxVideoBufferSize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# getMaxBufferSize

## Description

Returns the maximum video buffer memory size limit , in kilobytes.

This setting can be updated either by:

- calling the [setMaxVideoBufferSize](./setMaxVideoBufferSize.md) method.
- instanciating an RxPlayer with a `maxVideoBufferSize` property set.

## Syntax

```js
const bufferSize = player.getMaxBufferSize();
```

- **return value** `number`: Maximum buffer memory size limit,
in kilobytes.
40 changes: 40 additions & 0 deletions doc/api/Buffer_Control/setMaxVideoBufferSize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# setMaxVideoBufferSize

## Description

Set the maximum memory the video buffer can take up in the memory, in kilobytes
Defaults at `Infinity`

Once this value is reached, the player won't try to download new video
segments anymore.

This feature was designed with devices that have limited memory and trying to play very
high bitrates tracks in minds.
peaBerberian marked this conversation as resolved.
Show resolved Hide resolved

However on some custom targets, or just to better control the memory footprint
of the player, you might want to set this limit.

You can set it to `Infinity` to remove this limit and just let the browser do
this job instead.

<div class="warning">
This option will have no effects if we didn't buffer at least <b>MIN_BUFFER_LENGTH</b>
<i>( defaults at 5sec )</i>
</div>

<div class="warning">
In <i>DirectFile</i> mode (see <a
href="../Loading_a_Content.md#transport">loadVideo options</a>),
this method has no effect.
</div>

## Syntax

```js
player.setMaxVideoBufferSize(bufferSize);
```

- **arguments**:

1. _bufferSize_ `number`: Maximum amount of memory the buffer can download,
in kilobytes
25 changes: 25 additions & 0 deletions doc/api/Creating_a_Player.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,31 @@ This option will have no effect for contents loaded in <i>Directfile</i>
mode (see <a href="./Loading_a_Content.md#transport">loadVideo options</a>).
</div>

### maxVideoBufferSize

_type_: `Number|undefined`

_defaults_: `Infinity`

Set the maximum size of video the buffer in the memory, in kilobytes (kb).
Once this value is reached, the player won't try to download new video
segments anymore

<div class="warning">
The internal checks of the RxPlayer is based on an estimation of what the RxPlayer think
is currently buffered and an estimation of the size of the next segments.
</div>

<div class="warning">
This option will have no effects if we didn't buffer at least <b>MIN_BUFFER_LENGTH</b>
<i>( defaults at 5sec )</i>
</div>
peaBerberian marked this conversation as resolved.
Show resolved Hide resolved

<div class="warning">
This option will have no effect for contents loaded in <i>Directfile</i>
mode (see <a href="./Loading_a_Content.md#transport">loadVideo options</a>).
</div>

### preferredAudioTracks

_type_: `Array.<Object|null>`
Expand Down
29 changes: 29 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ export default {
*/
DEFAULT_WANTED_BUFFER_AHEAD: 30,

/**
* Default video buffer memory limit in kilobytes.
* Once enough video content has been downloaded to fill the buffer up to
* DEFAULT_MAX_VIDEO_BUFFER_SIZE , we will stop downloading
* content.
* @type {Number}
*/
DEFAULT_MAX_VIDEO_BUFFER_SIZE: Infinity,

/**
* Default max buffer size ahead of the current position in seconds.
* The buffer _after_ this limit will be garbage collected.
Expand Down Expand Up @@ -1222,4 +1231,24 @@ export default {
* there can be in that history.
*/
BUFFERED_HISTORY_MAXIMUM_ENTRIES: 200,

/**
* Minimum buffer (in seconds) we should have, regardless of memory
* constraints
*/
MIN_BUFFER_LENGTH : 5,

/**
* Minimum buffer in seconds ahead relative to current time
* we should be able to download
* Before trying to agressively free up memory
*/
MIN_BUFFER_DISTANCE_BEFORE_CLEAN_UP: 10,

/**
* Distance in seconds behind the current position
* the player will free up to in the case we agressively free up memory
* It is set to avoid playback issues
*/
UPTO_CURRENT_POSITION_CLEANUP : 5,
peaBerberian marked this conversation as resolved.
Show resolved Hide resolved
};
2 changes: 2 additions & 0 deletions src/core/api/__tests__/option_utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const {
DEFAULT_THROTTLE_WHEN_HIDDEN,
DEFAULT_THROTTLE_VIDEO_BITRATE_WHEN_HIDDEN,
DEFAULT_WANTED_BUFFER_AHEAD,
DEFAULT_MAX_VIDEO_BUFFER_SIZE,
} = config;

describe("API - parseConstructorOptions", () => {
Expand All @@ -77,6 +78,7 @@ describe("API - parseConstructorOptions", () => {
const videoElement = document.createElement("video");

const defaultConstructorOptions = {
maxVideoBufferSize: DEFAULT_MAX_VIDEO_BUFFER_SIZE,
maxBufferAhead: DEFAULT_MAX_BUFFER_AHEAD,
maxBufferBehind: DEFAULT_MAX_BUFFER_BEHIND,
wantedBufferAhead: DEFAULT_WANTED_BUFFER_AHEAD,
Expand Down
Loading