This is an open-source project created to enable customers to integrate the Bitmovin Player into React projects. It has been created to provide customers with a starting point, which can be built upon through active collaboration and contributions. We look forward to seeing this library expand and grow.
npm i bitmovin-player-react bitmovin-player bitmovin-player-ui --save
- Add
import "bitmovin-player-ui/dist/css/bitmovinplayer-ui.css";
to your entry point file - Use the player in your React components:
import { PlayerConfig, SourceConfig } from "bitmovin-player";
import { BitmovinPlayer } from "bitmovin-player-react";
import { Fragment } from "react";
const playerConfig: PlayerConfig = {
key: "<key>",
playback: {
muted: true,
autoplay: true,
},
};
const playerSource: SourceConfig = {
hls: "https://cdn.bitmovin.com/content/assets/streams-sample-video/sintel/m3u8/index.m3u8",
};
export function MyComponent() {
return (
<Fragment>
<h1>Simple demo</h1>
<BitmovinPlayer config={playerConfig} source={playerSource} />
</Fragment>
);
}
BitmovinPlayer
keeps track of the source config and reloads the source on changes:
const playerSources: Array<SourceConfig | undefined> = [
{
hls: "https://cdn.bitmovin.com/content/assets/streams-sample-video/sintel/m3u8/index.m3u8",
},
{
hls: "https://cdn.bitmovin.com/content/assets/streams-sample-video/tos/m3u8/index.m3u8",
},
// To demonstrate that the source can be unloaded as well.
undefined,
];
export function MyComponent() {
const [playerSource, setPlayerSource] = useState(playerSources[0]);
useEffect(() => {
let lastSourceIndex = 0;
const intervalId = setInterval(() => {
const newIndex = ++lastSourceIndex % playerSources.length;
console.log(`Switching to source ${newIndex}`, playerSources[newIndex]);
setPlayerSource(playerSources[newIndex]);
}, 15_000);
return () => clearInterval(intervalId);
}, []);
return (
<Fragment>
<h1>Dynamic source demo</h1>
<BitmovinPlayer config={playerConfig} source={playerSource} />
</Fragment>
);
}
BitmovinPlayer
keeps track of the player config and UI config and reinitializes the player (destroys the old instance and creates a new one) on changes :
const playerConfigs: Array<PlayerConfig> = [
{
key: "<key>",
playback: {
autoplay: true,
muted: true,
},
},
{
key: "<key>",
playback: {
autoplay: false,
muted: false,
},
},
];
export function MyComponent() {
const [playerConfig, setPlayerConfig] = useState(playerConfigs[0]);
useEffect(() => {
let lastConfigIndex = 0;
const intervalId = setInterval(() => {
const newIndex = ++lastConfigIndex % playerConfigs.length;
console.log(`Switching to player config ${newIndex}`, playerConfigs[newIndex]);
setPlayerConfig(playerConfigs[newIndex]);
}, 15_000);
return () => clearInterval(intervalId);
}, []);
return (
<Fragment>
<h1>Dynamic player config demo</h1>
<BitmovinPlayer config={playerConfig} source={playerSource} />
</Fragment>
);
}
The same applies to the customUi
object.
import { useMemo } from "react";
import { PlayerConfig, PlayerEvent } from "bitmovin-player";
export function MyComponent() {
const playerConfig: PlayerConfig = useMemo(
() => ({
key: '<key>',
playback: {
muted: true,
autoplay: true,
},
events: {
[PlayerEvent.Play]: event => {
console.log('Play event fired', event);
},
},
}),
[],
);
return (
<Fragment>
<h1>Events demo</h1>
<BitmovinPlayer config={playerConfig} source={playerSource} />
</Fragment>
);
}
import { PlayerAPI } from "bitmovin-player";
export function MyComponent() {
const handlePlayerRef = (player: PlayerAPI) => {
console.log("Player version", player.version);
};
return (
<Fragment>
<h1>Player instance demo</h1>
<BitmovinPlayer
playerRef={handlePlayerRef}
config={playerConfig}
source={playerSource}
/>
</Fragment>
);
}
You can use UIContainer
from https://www.npmjs.com/package/bitmovin-player-ui to customize the player UI:
import { PlaybackToggleOverlay, UIContainer, CustomUi } from "bitmovin-player-ui";
// Ensure this function returns a new instance of the `UIContainer` on every call.
const uiContainerFactory = () =>
new UIContainer({
components: [new PlaybackToggleOverlay()],
});
const customUi: CustomUi = {
containerFactory: uiContainerFactory
};
export function MyComponent() {
return (
<Fragment>
<h1>UI container demo</h1>
<BitmovinPlayer
source={playerSource}
config={playerConfig}
customUi={customUi}
/>
</Fragment>
);
}
You can use UIVariant
s from https://www.npmjs.com/package/bitmovin-player-ui to customize the player UI:
import { UIVariant, CustomUi } from "bitmovin-player-ui";
// Ensure this function returns a new instance of the `UIVariant[]` on every call.
const uiVariantsFactory = (): UIVariant[] => [
{
ui: new UIContainer({
components: [
new PlaybackToggleOverlay(),
new ControlBar({
components: [new SeekBar()],
hidden: false,
}),
],
}),
condition: (context) => context.isFullscreen,
},
{
ui: new UIContainer({
components: [new PlaybackToggleOverlay()],
}),
condition: (context) => !context.isFullscreen,
},
];
const customUi: CustomUi = {
variantsFactory: uiVariantsFactory
};
export function MyComponent() {
return (
<Fragment>
<h1>UI variants demo</h1>
<BitmovinPlayer
source={playerSource}
config={playerConfig}
customUi={customUi}
/>
</Fragment>
);
}
You either can implement your own CSS for the default player UI or build on top of bitmovin-player-ui/dist/css/bitmovinplayer-ui.css
.
Create a new CSS file:
/* customStyles.css */
.bmpui-ui-playbacktimelabel {
color: red;
}
Import the CSS file:
import "./customStyles.css";
export function MyComponent() {
return (
<Fragment>
<h1>Custom CSS demo</h1>
<BitmovinPlayer source={playerSource} config={playerConfig} />
</Fragment>
);
}
import { PlayerConfig } from "bitmovin-player";
const playerConfig: PlayerConfig = {
key: "<key>",
playback: {
muted: true,
autoplay: true,
},
// Disable UI
ui: false,
};
export function MyComponent() {
return (
<Fragment>
<h1>Disable UI demo</h1>
<BitmovinPlayer
source={playerSource}
config={playerConfig}
/>
</Fragment>
);
}
export function MyComponent() {
const [_counter, setCounter] = useState(0);
// This will create a new source object on every render and the player will be reloaded unnecessarily.
const playerSource: SourceConfig = {
hls: "https://cdn.bitmovin.com/content/assets/streams-sample-video/sintel/m3u8/index.m3u8",
};
useEffect(() => {
const intervalId = setInterval(() => {
setCounter((previousCounter) => previousCounter + 1);
}, 500);
return () => clearInterval(intervalId);
}, []);
return (
<Fragment>
<h1>Wrong source usage demo</h1>
<BitmovinPlayer config={playerConfig} source={playerSource} />
</Fragment>
);
}
Instead do one of the following:
- Create a source object outside of the component (refer to the "Simple demo" above)
- Use
useState
(refer to the "Dynamic source demo" above) - Use
useMemo
:
The same applies to the config
, source
, and customUi
objects.
export function MyComponent() {
const [_counter, setCounter] = useState(0);
// Ensure that the source object is created only once.
const playerSource: SourceConfig = useMemo(
() => ({
hls: "https://cdn.bitmovin.com/content/assets/streams-sample-video/sintel/m3u8/index.m3u8",
}),
// Add dependencies here if needed to build the source object.
[],
);
useEffect(() => {
const intervalId = setInterval(() => {
setCounter((previousCounter) => previousCounter + 1);
}, 500);
return () => clearInterval(intervalId);
}, []);
return (
<Fragment>
<h1>Right source usage demo</h1>
<BitmovinPlayer config={playerConfig} source={playerSource} />
</Fragment>
);
}
As an open source project, this library is not part of a regular maintenance or update schedule and is updated on an adhoc basis when contributions are made.
We are pleased to accept changes, updates and fixes from the community wishing to use and expand this project. Bitmovin will review any Pull Requests made. We do our best to provide timely feedback, but please note that no SLAs apply. New releases are tagged and published on our discretion. Please see CONTRIBUTING.md for more details on how to contribute.
If you see something missing that might be useful but are unable to contribute the feature yourself, please feel free to submit a feature request through the Bitmovin Community. Feature suggestions will be considered by Bitmovin’s Product team for future roadmap plans.
If you come across a bug related to the Bitmovin Player React, please raise this through the support ticketing system accessible in your Bitmovin Dashboard.
As an open-source project and not a core product offering, any request, issue or query related to this project is excluded from any SLA and Support terms that a customer might have with either Bitmovin or another third-party service provider or Company contributing to this project. Any and all updates are purely at the contributor's discretion.
Should you need further help, please raise your request to your Bitmovin account team. We can assist in a number of ways, from providing you professional services help to putting you in touch with preferred system integrators who can work with you to achieve your goals.