Skip to content

Commit

Permalink
Merge pull request #1308 from canalplus/feat/reload-keySystems
Browse files Browse the repository at this point in the history
Add the possibility to set a new `keySystems` option on the `reload` API
  • Loading branch information
peaBerberian committed Dec 19, 2023
2 parents d1fde0d + d34dafb commit cb6b2a3
Show file tree
Hide file tree
Showing 66 changed files with 1,792 additions and 596 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## Unreleased

### Features

- Add `getLivePosition` RxPlayer method [#1300]
- Add `startAt.fromLivePosition` `loadVideo` option [#1300]
- Add the possibility to set a new `keySystems` option on the `reload` API [#1308]

### Bug Fixes

- Fix subtitles "blinking" in some specific conditions, especially with some DASH low-latency contents [#1314]
- DASH: Fix Period overlap resolution logic for when the first Period is removed [#1311]
- Fix export of the `LOCAL_MANIFEST` experimental feature [#1305]

### Other improvements

- DASH: rely on SCTE214 `supplementalCodecs` instead of `codecs` if it's supported to better support backward compatible Dolby Vision contents [#1307]
- DASH: Provide better support of the `availabilityTimeOffset` attribute [#1300]
- DEBUG_ELEMENT: Add unsupported and undecipherable bitrates to the debug element [#1321]
- DEBUG_ELEMENT: update buffer graph maximum size so it becomes more readable for lengthy contents [#1316]
- DEBUG_ELEMENT: always synchronize inventory of segments before rendering it [#1317]


## v3.32.1 (2023-10-19)

### Features
Expand Down
2 changes: 1 addition & 1 deletion FILES.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ At the time of writing, there are two distinct demos:

## `dist/`: Builds

The `demo/` directory stores the player builds of the last version released.
The `dist/` directory stores the player builds of the last version released.

Contains the minified (``rx-player.min.js``) and the non-minified files
(``rx-player.js``). Both are automatically generated with scripts at every new
Expand Down
35 changes: 2 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,21 +179,11 @@ Demo pages for our previous versions are also available



## Your questions ##############################################################

You can ask directly your questions about the project on [our
gitter](https://gitter.im/canalplus/rx-player).
We will try our best to answer them as quickly as possible.



## Contribute ##################################################################

Details on how to contribute is written in the [CONTRIBUTING.md
file](./CONTRIBUTING.md) at the root of this repository.

If you need more information, you can contact us via our [gitter
room](https://gitter.im/canalplus/rx-player).


### Dependencies ###############################################################
Expand Down Expand Up @@ -238,7 +228,7 @@ Canal+ Group is a media company with many advanced needs when it comes to media
playback: it provides both live and VoD stream with multiple encryption
requirements, supports a very large panel of devices and has many other
specificities (like adult content restrictions, ad-insertion, Peer-To-Peer
integration...).
integration, low-latency live streaming...).

When the time came to switch from a plugin-based web player approach to an HTML5
one back in 2015, no media player had the key features we wanted, and including
Expand All @@ -249,7 +239,7 @@ The R&D department of Canal+ Group thus started to work on a new featureful
media-player: the RxPlayer. To both help and profit from the community, it also
decided to share it to everyone under a permissive open-source licence.

Now, more than 6 years later, the RxPlayer continues to evolve at the same fast
Now, more than 8 years later, the RxPlayer continues to evolve at the same fast
pace to include a lot of features and improvements you may not find in other
media players.
You can look at our
Expand Down Expand Up @@ -296,24 +286,3 @@ them. Amongst those:
risks always low.

\* In "directfile" mode, on compatible browsers


## Target support ##############################################################

Here is a basic list of supported platforms:

| | Chrome | IE [1] | Edge | Firefox | Safari | Opera |
|-------------|:-------:|:-------:|:------:|:---------:|:--------:|:-------:|
| Windows | >= 30 | >= 11 | >= 12 | >= 42 | >= 8 | >= 25 |
| OSX | >= 30 | - | - | >= 42 | >= 8 | >= 25 |
| Linux | >= 37 | - | - | >= 42 | - | >= 25 |
| Android [2] | >= 30 | - | - | >= 42 | - | >= 15 |
| iOS | No | - | - | No | No | No |

[1] Only on Windows >= 8.

[2] Android version >= 4.2

And more. A good way to know if the browser should be supported by our player is
to go on the page https://www.youtube.com/html5 and check for "Media Source
Extensions" support.
8 changes: 5 additions & 3 deletions demo/full/scripts/controllers/ControlBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function ControlBar({
const isStopped = useModuleState(player, "isStopped");
const liveGap = useModuleState(player, "liveGap");
const lowLatencyMode = useModuleState(player, "lowLatencyMode");
const livePosition = useModuleState(player, "livePosition");
const maximumPosition = useModuleState(player, "maximumPosition");
const playbackRate = useModuleState(player, "playbackRate");

Expand Down Expand Up @@ -79,15 +80,16 @@ function ControlBar({
const isAtLiveEdge = isLive && isCloseToLive && !isCatchingUp;

const onLiveDotClick = React.useCallback(() => {
if (maximumPosition == null) {
const livePos = livePosition ?? maximumPosition;
if (livePos == null) {
/* eslint-disable-next-line no-console */
console.error("Cannot go back to live: live position not found");
return;
}
if (!isAtLiveEdge) {
player.actions.seek(maximumPosition - (lowLatencyMode ? 4 : 10));
player.actions.seek(livePos - (lowLatencyMode ? 4 : 10));
}
}, [isAtLiveEdge, player, maximumPosition, lowLatencyMode]);
}, [isAtLiveEdge, player, livePosition, maximumPosition, lowLatencyMode]);

return (
<div className="controls-bar-container">
Expand Down
3 changes: 2 additions & 1 deletion demo/full/scripts/controllers/ProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function ProgressBar({
const isContentLoaded = useModuleState(player, "isContentLoaded");
const isLive = useModuleState(player, "isLive");
const minimumPosition = useModuleState(player, "minimumPosition");
const livePosition = useModuleState(player, "livePosition");
const maximumPosition = useModuleState(player, "maximumPosition");

const [timeIndicatorVisible, setTimeIndicatorVisible] = React.useState(false);
Expand Down Expand Up @@ -189,7 +190,7 @@ function ProgressBar({
onMouseMove={onMouseMove}
position={currentTime}
minimumPosition={minimumPosition}
maximumPosition={maximumPosition}
maximumPosition={livePosition ?? maximumPosition}
bufferGap={bufferGap}
/>
}
Expand Down
10 changes: 5 additions & 5 deletions demo/full/scripts/modules/player/catchUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@ export default class CatchUpModeController {
this._state.updateBulk({ isCatchingUp: false, playbackRate: 1 });
} else {
const checkCatchUp = () => {
const maximumPosition = this._rxPlayer.getMaximumPosition();
if (maximumPosition === null) {
const livePos = this._rxPlayer.getLivePosition() ??
this._rxPlayer.getMaximumPosition();
if (livePos === null) {
this._rxPlayer.setPlaybackRate(1);
this._state.updateBulk({ isCatchingUp: false, playbackRate: 1 });
return;
}
const position = this._rxPlayer.getPosition();
const liveGap = maximumPosition - position;
const liveGap = livePos - position;
if (liveGap >= CATCH_UP_SEEKING_STEP) {
// If we're too far from the live to just change the playback rate,
// seek directly close to live
this._rxPlayer
.seekTo(maximumPosition - LIVE_GAP_GOAL_WHEN_CATCHING_UP);
this._rxPlayer.seekTo(livePos - LIVE_GAP_GOAL_WHEN_CATCHING_UP);
this._rxPlayer.setPlaybackRate(1);
this._state.updateBulk({ isCatchingUp: false, playbackRate: 1 });
return;
Expand Down
11 changes: 8 additions & 3 deletions demo/full/scripts/modules/player/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,24 @@ function linkPlayerEventsToState(
const position = player.getPosition();
const duration = player.getVideoDuration();
const videoTrack = player.getVideoTrack();
const livePosition = player.getLivePosition();
const maximumPosition = player.getMaximumPosition();
let bufferGap = player.getVideoBufferGap();
bufferGap = !isFinite(bufferGap) || isNaN(bufferGap) ?
0 :
bufferGap;

const livePos = livePosition ?? maximumPosition;
state.updateBulk({
currentTime: player.getPosition(),
wallClockDiff: player.getWallClockTime() - position,
bufferGap,
duration: Number.isNaN(duration) ? undefined : duration,
livePosition,
minimumPosition: player.getMinimumPosition(),
maximumPosition: player.getMaximumPosition(),
liveGap: typeof maximumPosition === "number" ?
maximumPosition - player.getPosition() :
maximumPosition,
liveGap: typeof livePos === "number" ?
livePos - player.getPosition() :
undefined,
playbackRate: player.getPlaybackRate(),
videoTrackHasTrickMode: videoTrack !== null &&
Expand Down Expand Up @@ -210,6 +214,7 @@ function linkPlayerEventsToState(
stateUpdates.duration = undefined;
stateUpdates.minimumPosition = undefined;
stateUpdates.maximumPosition = undefined;
stateUpdates.livePosition = undefined;
break;
}

Expand Down
2 changes: 2 additions & 0 deletions demo/full/scripts/modules/player/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export interface IPlayerModuleState {
liveGap: number | undefined;
loadedVideo: ILoadVideoOptions | null;
lowLatencyMode: boolean;
livePosition: null | undefined | number;
maximumPosition: null | undefined | number;
minimumPosition: null | undefined | number;
playbackRate: number;
Expand Down Expand Up @@ -185,6 +186,7 @@ const PlayerModule = declareModule(
liveGap: undefined,
loadedVideo: null,
lowLatencyMode: false,
livePosition: undefined,
maximumPosition: undefined,
minimumPosition: undefined,
playbackRate: 1,
Expand Down
11 changes: 11 additions & 0 deletions doc/api/Basic_Methods/reload.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ The options argument is an object containing :
content was playing the last time it was played and stay in the `"LOADED"`
state (and paused) if it was paused last time it was played.

- _keySystems_ (`Array.<Object> | undefined`): If set, a new configuration will
be set on this reloaded content regarding its decryption.

The value of this property follows the exact same structure than for the
original `loadVideo` call, it is described in the [decryption options
documentation page](../Decryption_Options.md).

You might for example want to update that way the `keySystems` option compared
to the one of the original `loadVideo` call when you suspect that there is a
decryption-related issue with the original `keySystems` given.

Note that despite this method's name, the player will not go through the
`RELOADING` state while reloading the content but through the regular `LOADING`
state - as if `loadVideo` was called on that same content again.
Expand Down
10 changes: 10 additions & 0 deletions doc/api/Loading_a_Content.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ can be either:
- for VoD contents, it is the difference between the starting position and
the end position of the content.


- **fromLivePosition** relative position relative to the content's live edge
(for live contents, it is the position that is intended to be broadcasted
at the current time) if it makes sense, in seconds. Should be a negative
number.

If the live edge is unknown or if it does not make sense for the current
content (for example, it won't make sense for a VoD content), that setting
repeats the same behavior than **fromLastPosition**.

- **percentage** (`Number`): percentage of the wanted position. `0` being
the minimum position possible (0 for static content, buffer depth for
dynamic contents) and `100` being the maximum position possible
Expand Down
16 changes: 14 additions & 2 deletions doc/api/Miscellaneous/Debug_Element.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,20 @@ reflect exactly what's going on at a particular point in time.
- **vt**: _Video tracks_. List of the video tracks' `id` property. The line begins with a number indicating the number of available video tracks, followed by `:`, followed by each video track's id separated by a space. The current video track is prepended by a `*` character.
- **at**: _Audio tracks_. List of the audio tracks' `id` property. The line begins with a number indicating the number of available audio tracks, followed by `:`, followed by each audio track's id separated by a space. The current audio track is prepended by a `*` character.
- **tt**: _Text tracks_. List of the text tracks' `id` property. The line begins with a number indicating the number of available text tracks, followed by `:`, followed by each text track's id separated by a space. The current text track is prepended by a `*` character.
- **vb**: _Video Bitrates_. The available video bitrates in the current video track, separated by a space.
- **ab**: _Audio Bitrates_. The available audio bitrates in the current audio track, separated by a space.
- **vb**: _Video Bitrates_. The available video bitrates in the current
video track, separated by a space.
Each bitrate value can optionally be followed by an "`U!`", in which case
the codec of the corresponding Representation is unsupported, and/or be
followed by an "`E!`", in which case it is undecipherable currently.
In both of those cases the corresponding video Representation won't be
played by the RxPlayer.
- **ab**: _Audio Bitrates_. The available audio bitrates in the current
audio track, separated by a space.
Each bitrate value can optionally be followed by an "`U!`", in which case
the codec of the corresponding Representation is unsupported, and/or be
followed by an "`E!`", in which case it is undecipherable currently.
In both of those cases the corresponding audio Representation won't be
played by the RxPlayer.

- Buffer information
- **vbuf**: _Graphical representation of the video buffer_. The red rectangle indicates the current position, the different colors indicate different video qualities in the buffer.
Expand Down
2 changes: 1 addition & 1 deletion doc/api/Miscellaneous/Low_Latency.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ rxPlayer.loadVideo({
url: "https://www.example.com/content.mpd",
transport: "dash",
lowLatencyMode: true,
startAt: { fromLastPosition: 2 }, // Play 2 seconds from the live edge instead
startAt: { fromLivePosition: 2 }, // Play 2 seconds from the live edge instead
// (beware of much more frequent rebuffering
// risks)
});
Expand Down
Loading

0 comments on commit cb6b2a3

Please sign in to comment.