Skip to content

Commit

Permalink
Merge pull request #1041 from canalplus/feat/add-memory-size-buffer
Browse files Browse the repository at this point in the history
Add `maxVideoBufferSize` option to limit the amount of video data (in kilobytes?) the RxPlayer will push on low-end devices
  • Loading branch information
achrafl0 authored Mar 17, 2022
2 parents 90ed273 + f6b933e commit b30389d
Show file tree
Hide file tree
Showing 31 changed files with 611 additions and 83 deletions.
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": "./setMaxVideoBufferSize.md",
"displayName": "setMaxVideoBufferSize"
},
{
"path": "./getMaxVideoBufferSize.md",
"displayName": "getMaxVideoBufferSize"
}
]
}
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.
39 changes: 39 additions & 0 deletions doc/api/Buffer_Control/setMaxVideoBufferSize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 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 representations in minds.

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">
The limit set by `setMaxVideoBufferSize` is approximative, and bypassed in edge case scenarios if we dont have enough buffer because of this limitation.
</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
31 changes: 31 additions & 0 deletions doc/api/Creating_a_Player.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,37 @@ 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. The limit is approximative as it's based on internal estimation.

<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">
In <i>DirectFile</i> mode (see <a
href="../Loading_a_Content.md#transport">loadVideo options</a>),
this method has no effect.
</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>

<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
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 @@ -65,6 +65,7 @@ describe("API - parseConstructorOptions", () => {
DEFAULT_INITIAL_BITRATES,
DEFAULT_LIMIT_VIDEO_WIDTH,
// DEFAULT_MANUAL_BITRATE_SWITCHING_MODE,
DEFAULT_MAX_VIDEO_BUFFER_SIZE,
DEFAULT_MIN_BITRATES,
DEFAULT_MAX_BITRATES,
DEFAULT_MAX_BUFFER_AHEAD,
Expand All @@ -76,6 +77,7 @@ describe("API - parseConstructorOptions", () => {
DEFAULT_WANTED_BUFFER_AHEAD,
} = config.getCurrent();
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
18 changes: 17 additions & 1 deletion src/core/api/option_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ type IParsedStartAtOption = { position : number } |
export interface IConstructorOptions { maxBufferAhead? : number;
maxBufferBehind? : number;
wantedBufferAhead? : number;
maxVideoBufferSize?: number;

limitVideoWidth? : boolean;
throttleWhenHidden? : boolean;
Expand All @@ -201,7 +202,7 @@ export interface IParsedConstructorOptions {
maxBufferAhead : number;
maxBufferBehind : number;
wantedBufferAhead : number;

maxVideoBufferSize : number;
limitVideoWidth : boolean;
throttleWhenHidden : boolean;
throttleVideoBitrateWhenHidden : boolean;
Expand Down Expand Up @@ -311,6 +312,7 @@ function parseConstructorOptions(
let maxBufferAhead : number;
let maxBufferBehind : number;
let wantedBufferAhead : number;
let maxVideoBufferSize : number;

let throttleWhenHidden : boolean;
let throttleVideoBitrateWhenHidden : boolean;
Expand All @@ -333,6 +335,7 @@ function parseConstructorOptions(
DEFAULT_MAX_BITRATES,
DEFAULT_MAX_BUFFER_AHEAD,
DEFAULT_MAX_BUFFER_BEHIND,
DEFAULT_MAX_VIDEO_BUFFER_SIZE,
DEFAULT_STOP_AT_END,
DEFAULT_THROTTLE_WHEN_HIDDEN,
DEFAULT_THROTTLE_VIDEO_BITRATE_WHEN_HIDDEN,
Expand Down Expand Up @@ -367,6 +370,18 @@ function parseConstructorOptions(
}
}

if (isNullOrUndefined(options.maxVideoBufferSize)) {
maxVideoBufferSize = DEFAULT_MAX_VIDEO_BUFFER_SIZE;
} else {
maxVideoBufferSize = Number(options.maxVideoBufferSize);
if (isNaN(maxVideoBufferSize)) {
/* eslint-disable max-len */
throw new Error("Invalid maxVideoBufferSize parameter. Should be a number.");
/* eslint-enable max-len */
}
}


const limitVideoWidth = isNullOrUndefined(options.limitVideoWidth) ?
DEFAULT_LIMIT_VIDEO_WIDTH :
!!options.limitVideoWidth;
Expand Down Expand Up @@ -508,6 +523,7 @@ function parseConstructorOptions(
limitVideoWidth,
videoElement,
wantedBufferAhead,
maxVideoBufferSize,
throttleWhenHidden,
throttleVideoBitrateWhenHidden,
preferredAudioTracks,
Expand Down
Loading

0 comments on commit b30389d

Please sign in to comment.