mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Add ability to set playback speed on motion playback (#10628)
* Allow control of playback rate on motion page * Apply playback rate
This commit is contained in:
parent
76a114a3cd
commit
63bf986e08
@ -160,6 +160,7 @@ export default function HlsVideoPlayer({
|
|||||||
show={controls}
|
show={controls}
|
||||||
controlsOpen={controlsOpen}
|
controlsOpen={controlsOpen}
|
||||||
setControlsOpen={setControlsOpen}
|
setControlsOpen={setControlsOpen}
|
||||||
|
playbackRate={videoRef.current?.playbackRate ?? 1}
|
||||||
onPlayPause={(play) => {
|
onPlayPause={(play) => {
|
||||||
if (!videoRef.current) {
|
if (!videoRef.current) {
|
||||||
return;
|
return;
|
||||||
@ -180,6 +181,9 @@ export default function HlsVideoPlayer({
|
|||||||
|
|
||||||
videoRef.current.currentTime = Math.max(0, currentTime + diff);
|
videoRef.current.currentTime = Math.max(0, currentTime + diff);
|
||||||
}}
|
}}
|
||||||
|
onSetPlaybackRate={(rate) =>
|
||||||
|
videoRef.current ? (videoRef.current.playbackRate = rate) : null
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,6 +30,7 @@ const CONTROLS_DEFAULT: VideoControls = {
|
|||||||
seek: true,
|
seek: true,
|
||||||
playbackRate: true,
|
playbackRate: true,
|
||||||
};
|
};
|
||||||
|
const PLAYBACK_RATE_DEFAULT = isSafari ? [0.5, 1, 2] : [0.5, 1, 2, 4, 8, 16];
|
||||||
|
|
||||||
type VideoControlsProps = {
|
type VideoControlsProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -38,9 +39,12 @@ type VideoControlsProps = {
|
|||||||
isPlaying: boolean;
|
isPlaying: boolean;
|
||||||
show: boolean;
|
show: boolean;
|
||||||
controlsOpen?: boolean;
|
controlsOpen?: boolean;
|
||||||
|
playbackRates?: number[];
|
||||||
|
playbackRate: number;
|
||||||
setControlsOpen?: (open: boolean) => void;
|
setControlsOpen?: (open: boolean) => void;
|
||||||
onPlayPause: (play: boolean) => void;
|
onPlayPause: (play: boolean) => void;
|
||||||
onSeek: (diff: number) => void;
|
onSeek: (diff: number) => void;
|
||||||
|
onSetPlaybackRate: (rate: number) => void;
|
||||||
};
|
};
|
||||||
export default function VideoControls({
|
export default function VideoControls({
|
||||||
className,
|
className,
|
||||||
@ -49,18 +53,13 @@ export default function VideoControls({
|
|||||||
isPlaying,
|
isPlaying,
|
||||||
show,
|
show,
|
||||||
controlsOpen,
|
controlsOpen,
|
||||||
|
playbackRates = PLAYBACK_RATE_DEFAULT,
|
||||||
|
playbackRate,
|
||||||
setControlsOpen,
|
setControlsOpen,
|
||||||
onPlayPause,
|
onPlayPause,
|
||||||
onSeek,
|
onSeek,
|
||||||
|
onSetPlaybackRate,
|
||||||
}: VideoControlsProps) {
|
}: VideoControlsProps) {
|
||||||
const playbackRates = useMemo(() => {
|
|
||||||
if (isSafari) {
|
|
||||||
return [0.5, 1, 2];
|
|
||||||
} else {
|
|
||||||
return [0.5, 1, 2, 4, 8, 16];
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onReplay = useCallback(
|
const onReplay = useCallback(
|
||||||
(e: React.MouseEvent<SVGElement>) => {
|
(e: React.MouseEvent<SVGElement>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -177,7 +176,7 @@ export default function VideoControls({
|
|||||||
{features.seek && (
|
{features.seek && (
|
||||||
<MdForward10 className="size-5 cursor-pointer" onClick={onSkip} />
|
<MdForward10 className="size-5 cursor-pointer" onClick={onSkip} />
|
||||||
)}
|
)}
|
||||||
{video && features.playbackRate && (
|
{features.playbackRate && (
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
open={controlsOpen == true}
|
open={controlsOpen == true}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
@ -186,10 +185,10 @@ export default function VideoControls({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DropdownMenuTrigger>{`${video.playbackRate}x`}</DropdownMenuTrigger>
|
<DropdownMenuTrigger>{`${playbackRate}x`}</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<DropdownMenuContent>
|
||||||
<DropdownMenuRadioGroup
|
<DropdownMenuRadioGroup
|
||||||
onValueChange={(rate) => (video.playbackRate = parseFloat(rate))}
|
onValueChange={(rate) => onSetPlaybackRate(parseFloat(rate))}
|
||||||
>
|
>
|
||||||
{playbackRates.map((rate) => (
|
{playbackRates.map((rate) => (
|
||||||
<DropdownMenuRadioItem key={rate} value={rate.toString()}>
|
<DropdownMenuRadioItem key={rate} value={rate.toString()}>
|
||||||
|
@ -716,11 +716,15 @@ function MotionReview({
|
|||||||
|
|
||||||
// playback
|
// playback
|
||||||
|
|
||||||
|
const [playbackRate, setPlaybackRate] = useState(8);
|
||||||
|
const [controlsOpen, setControlsOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const interval = 500 / playbackRate;
|
||||||
const startTime = currentTime;
|
const startTime = currentTime;
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
const intervalId = setInterval(() => {
|
const intervalId = setInterval(() => {
|
||||||
@ -732,14 +736,14 @@ function MotionReview({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setCurrentTime(startTime + counter);
|
setCurrentTime(startTime + counter);
|
||||||
}, 60);
|
}, interval);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(intervalId);
|
clearInterval(intervalId);
|
||||||
};
|
};
|
||||||
// do not render when current time changes
|
// do not render when current time changes
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [playing]);
|
}, [playing, playbackRate]);
|
||||||
|
|
||||||
if (!relevantPreviews) {
|
if (!relevantPreviews) {
|
||||||
return <ActivityIndicator />;
|
return <ActivityIndicator />;
|
||||||
@ -815,9 +819,13 @@ function MotionReview({
|
|||||||
features={{
|
features={{
|
||||||
volume: false,
|
volume: false,
|
||||||
seek: true,
|
seek: true,
|
||||||
playbackRate: false,
|
playbackRate: true,
|
||||||
}}
|
}}
|
||||||
isPlaying={playing}
|
isPlaying={playing}
|
||||||
|
playbackRates={[4, 8, 12, 16]}
|
||||||
|
playbackRate={playbackRate}
|
||||||
|
controlsOpen={controlsOpen}
|
||||||
|
setControlsOpen={setControlsOpen}
|
||||||
onPlayPause={setPlaying}
|
onPlayPause={setPlaying}
|
||||||
onSeek={(diff) => {
|
onSeek={(diff) => {
|
||||||
const wasPlaying = playing;
|
const wasPlaying = playing;
|
||||||
@ -832,6 +840,7 @@ function MotionReview({
|
|||||||
setTimeout(() => setPlaying(true), 100);
|
setTimeout(() => setPlaying(true), 100);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onSetPlaybackRate={setPlaybackRate}
|
||||||
show={currentTime < timeRange.before - 4}
|
show={currentTime < timeRange.before - 4}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user