frigate/web-new/src/components/player/VideoPlayer.tsx

74 lines
2.1 KiB
TypeScript
Raw Normal View History

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,
},
onReady?: (player: Player) => void,
onDispose?: () => void,
}
export default function VideoPlayer({ children, options, seekOptions = {forward:30, backward: 10}, onReady = (_) => {}, onDispose = () => {} }: VideoPlayerProps) {
const videoRef = useRef<HTMLVideoElement | 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");
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>
);
}