|
1 | 1 | import { forwardRef, memo, MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'; |
2 | 2 | import { Block, Elem } from '../../utils/bem'; |
| 3 | +import { FF_LSDV_4711, isFF } from '../../utils/feature-flags'; |
3 | 4 | import { clamp, isDefined } from '../../utils/utilities'; |
4 | 5 | import './VideoCanvas.styl'; |
5 | 6 | import { MAX_ZOOM, MIN_ZOOM } from './VideoConstants'; |
@@ -35,6 +36,7 @@ type VideoProps = { |
35 | 36 | onFrameChange?: (frame: number, length: number) => void, |
36 | 37 | onEnded?: () => void, |
37 | 38 | onResize?: (dimensions: VideoDimentions) => void, |
| 39 | + onError?: (error: any) => void, |
38 | 40 | } |
39 | 41 |
|
40 | 42 | type PanOptions = { |
@@ -92,6 +94,7 @@ export const VideoCanvas = memo(forwardRef<VideoRef, VideoProps>((props, ref) => |
92 | 94 | const contextRef = useRef<CanvasRenderingContext2D | null>(); |
93 | 95 | const videoRef = useRef<HTMLVideoElement>(); |
94 | 96 | const supportedFileTypeRef = useRef<boolean|null>(null); |
| 97 | + const hasLoadedRef = useRef<boolean>(false); |
95 | 98 |
|
96 | 99 | const canvasWidth = useMemo(() => props.width ?? 600, [props.width]); |
97 | 100 | const canvasHeight = useMemo(() => props.height ?? 600, [props.height]); |
@@ -187,6 +190,7 @@ export const VideoCanvas = memo(forwardRef<VideoRef, VideoProps>((props, ref) => |
187 | 190 | if (!playing) updateFrame(true); |
188 | 191 |
|
189 | 192 | if (video.networkState === video.NETWORK_IDLE) { |
| 193 | + hasLoadedRef.current = true; |
190 | 194 | setBuffering(false); |
191 | 195 | } else { |
192 | 196 | setBuffering(true); |
@@ -224,6 +228,24 @@ export const VideoCanvas = memo(forwardRef<VideoRef, VideoProps>((props, ref) => |
224 | 228 | props.onPause?.(); |
225 | 229 | }, [props.onEnded]); |
226 | 230 |
|
| 231 | + const handleVideoError = useCallback(() => { |
| 232 | + if (!isFF(FF_LSDV_4711)) return; |
| 233 | + |
| 234 | + const video = videoRef.current; |
| 235 | + |
| 236 | + if (video?.error && hasLoadedRef.current) { |
| 237 | + hasLoadedRef.current = false; |
| 238 | + |
| 239 | + // If the video errored after loading, we can try to reload it |
| 240 | + // as it may have been a temporary network issue or signed url that expired |
| 241 | + video.load(); |
| 242 | + } else if (video) { |
| 243 | + // If the video never loaded and errored, we can't do anything about it |
| 244 | + // so report it to the consumer |
| 245 | + props.onError?.(video.error); |
| 246 | + } |
| 247 | + }, [props.onError]); |
| 248 | + |
227 | 249 | const handleAnimationFrame = () => { |
228 | 250 | updateFrame(); |
229 | 251 |
|
@@ -551,6 +573,7 @@ export const VideoCanvas = memo(forwardRef<VideoRef, VideoProps>((props, ref) => |
551 | 573 | onPlaying={handleVideoPlaying} |
552 | 574 | onWaiting={handleVideoWaiting} |
553 | 575 | onEnded={handleVideoEnded} |
| 576 | + onError={handleVideoError} |
554 | 577 | /> |
555 | 578 | </Block> |
556 | 579 | ); |
|
0 commit comments