forked from Github/frigate
89
web/src/components/player/VideoPlayer.tsx
Normal file
89
web/src/components/player/VideoPlayer.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { useEffect, useRef, ReactElement } from "react";
|
||||
import videojs from "video.js";
|
||||
import "videojs-playlist";
|
||||
import "video.js/dist/video-js.css";
|
||||
import Player from "video.js/dist/types/player";
|
||||
|
||||
type VideoPlayerProps = {
|
||||
children?: ReactElement | ReactElement[];
|
||||
options?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
seekOptions?: {
|
||||
forward?: number;
|
||||
backward?: number;
|
||||
};
|
||||
remotePlayback?: boolean;
|
||||
onReady?: (player: Player) => void;
|
||||
onDispose?: () => void;
|
||||
};
|
||||
|
||||
export default function VideoPlayer({
|
||||
children,
|
||||
options,
|
||||
seekOptions = { forward: 30, backward: 10 },
|
||||
remotePlayback = false,
|
||||
onReady = (_) => {},
|
||||
onDispose = () => {},
|
||||
}: VideoPlayerProps) {
|
||||
const videoRef = useRef<HTMLDivElement | null>(null);
|
||||
const playerRef = useRef<Player | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const defaultOptions = {
|
||||
controls: true,
|
||||
controlBar: {
|
||||
skipButtons: seekOptions,
|
||||
},
|
||||
playbackRates: [0.5, 1, 2, 4, 8],
|
||||
fluid: true,
|
||||
};
|
||||
|
||||
if (!videojs.browser.IS_FIREFOX) {
|
||||
defaultOptions.playbackRates.push(16);
|
||||
}
|
||||
|
||||
// Make sure Video.js player is only initialized once
|
||||
if (!playerRef.current) {
|
||||
// The Video.js player needs to be _inside_ the component el for React 18 Strict Mode.
|
||||
const videoElement = document.createElement(
|
||||
"video-js"
|
||||
) as HTMLVideoElement;
|
||||
videoElement.controls = true;
|
||||
videoElement.playsInline = true;
|
||||
videoElement.disableRemotePlayback = remotePlayback;
|
||||
videoElement.classList.add("small-player");
|
||||
videoElement.classList.add("video-js");
|
||||
videoElement.classList.add("vjs-default-skin");
|
||||
videoRef.current?.appendChild(videoElement);
|
||||
|
||||
const player = (playerRef.current = videojs(
|
||||
videoElement,
|
||||
{ ...defaultOptions, ...options },
|
||||
() => {
|
||||
onReady && onReady(player);
|
||||
}
|
||||
));
|
||||
}
|
||||
}, [options, videoRef]);
|
||||
|
||||
// Dispose the Video.js player when the functional component unmounts
|
||||
useEffect(() => {
|
||||
const player = playerRef.current;
|
||||
|
||||
return () => {
|
||||
if (player && !player.isDisposed()) {
|
||||
player.dispose();
|
||||
playerRef.current = null;
|
||||
onDispose();
|
||||
}
|
||||
};
|
||||
}, [playerRef]);
|
||||
|
||||
return (
|
||||
<div data-vjs-player>
|
||||
<div ref={videoRef} />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user