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:
Nicolas Mowen 2024-03-23 10:24:57 -06:00 committed by GitHub
parent 76a114a3cd
commit 63bf986e08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 14 deletions

View File

@ -160,6 +160,7 @@ export default function HlsVideoPlayer({
show={controls}
controlsOpen={controlsOpen}
setControlsOpen={setControlsOpen}
playbackRate={videoRef.current?.playbackRate ?? 1}
onPlayPause={(play) => {
if (!videoRef.current) {
return;
@ -180,6 +181,9 @@ export default function HlsVideoPlayer({
videoRef.current.currentTime = Math.max(0, currentTime + diff);
}}
onSetPlaybackRate={(rate) =>
videoRef.current ? (videoRef.current.playbackRate = rate) : null
}
/>
{children}
</div>

View File

@ -30,6 +30,7 @@ const CONTROLS_DEFAULT: VideoControls = {
seek: true,
playbackRate: true,
};
const PLAYBACK_RATE_DEFAULT = isSafari ? [0.5, 1, 2] : [0.5, 1, 2, 4, 8, 16];
type VideoControlsProps = {
className?: string;
@ -38,9 +39,12 @@ type VideoControlsProps = {
isPlaying: boolean;
show: boolean;
controlsOpen?: boolean;
playbackRates?: number[];
playbackRate: number;
setControlsOpen?: (open: boolean) => void;
onPlayPause: (play: boolean) => void;
onSeek: (diff: number) => void;
onSetPlaybackRate: (rate: number) => void;
};
export default function VideoControls({
className,
@ -49,18 +53,13 @@ export default function VideoControls({
isPlaying,
show,
controlsOpen,
playbackRates = PLAYBACK_RATE_DEFAULT,
playbackRate,
setControlsOpen,
onPlayPause,
onSeek,
onSetPlaybackRate,
}: VideoControlsProps) {
const playbackRates = useMemo(() => {
if (isSafari) {
return [0.5, 1, 2];
} else {
return [0.5, 1, 2, 4, 8, 16];
}
}, []);
const onReplay = useCallback(
(e: React.MouseEvent<SVGElement>) => {
e.stopPropagation();
@ -177,7 +176,7 @@ export default function VideoControls({
{features.seek && (
<MdForward10 className="size-5 cursor-pointer" onClick={onSkip} />
)}
{video && features.playbackRate && (
{features.playbackRate && (
<DropdownMenu
open={controlsOpen == true}
onOpenChange={(open) => {
@ -186,10 +185,10 @@ export default function VideoControls({
}
}}
>
<DropdownMenuTrigger>{`${video.playbackRate}x`}</DropdownMenuTrigger>
<DropdownMenuTrigger>{`${playbackRate}x`}</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuRadioGroup
onValueChange={(rate) => (video.playbackRate = parseFloat(rate))}
onValueChange={(rate) => onSetPlaybackRate(parseFloat(rate))}
>
{playbackRates.map((rate) => (
<DropdownMenuRadioItem key={rate} value={rate.toString()}>

View File

@ -716,11 +716,15 @@ function MotionReview({
// playback
const [playbackRate, setPlaybackRate] = useState(8);
const [controlsOpen, setControlsOpen] = useState(false);
useEffect(() => {
if (!playing) {
return;
}
const interval = 500 / playbackRate;
const startTime = currentTime;
let counter = 0;
const intervalId = setInterval(() => {
@ -732,14 +736,14 @@ function MotionReview({
}
setCurrentTime(startTime + counter);
}, 60);
}, interval);
return () => {
clearInterval(intervalId);
};
// do not render when current time changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [playing]);
}, [playing, playbackRate]);
if (!relevantPreviews) {
return <ActivityIndicator />;
@ -815,9 +819,13 @@ function MotionReview({
features={{
volume: false,
seek: true,
playbackRate: false,
playbackRate: true,
}}
isPlaying={playing}
playbackRates={[4, 8, 12, 16]}
playbackRate={playbackRate}
controlsOpen={controlsOpen}
setControlsOpen={setControlsOpen}
onPlayPause={setPlaying}
onSeek={(diff) => {
const wasPlaying = playing;
@ -832,6 +840,7 @@ function MotionReview({
setTimeout(() => setPlaying(true), 100);
}
}}
onSetPlaybackRate={setPlaybackRate}
show={currentTime < timeRange.before - 4}
/>
</>