mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Adjust MSE player playback rate logic (#13164)
* Fix MSE playback rate logic * don't adjust playback rate if we just started streaming * memoize onprogress
This commit is contained in:
parent
3a124dbb84
commit
8e31244fb3
@ -364,9 +364,11 @@ function MSEPlayer({
|
|||||||
const beta = 0.5; // steepness of exponential growth
|
const beta = 0.5; // steepness of exponential growth
|
||||||
|
|
||||||
// don't adjust playback rate if we're close enough to live
|
// don't adjust playback rate if we're close enough to live
|
||||||
|
// or if we just started streaming
|
||||||
if (
|
if (
|
||||||
(bufferTime <= bufferThreshold && bufferThreshold < 3) ||
|
((bufferTime <= bufferThreshold && bufferThreshold < 3) ||
|
||||||
bufferTime < 3
|
bufferTime < 3) &&
|
||||||
|
bufferTimes.current.length <= MAX_BUFFER_ENTRIES
|
||||||
) {
|
) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -374,6 +376,98 @@ function MSEPlayer({
|
|||||||
return Math.min(rate, 2);
|
return Math.min(rate, 2);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onProgress = useCallback(() => {
|
||||||
|
const bufferTime = getBufferedTime(videoRef.current);
|
||||||
|
|
||||||
|
if (
|
||||||
|
videoRef.current &&
|
||||||
|
(videoRef.current.playbackRate === 1 || bufferTime < 3)
|
||||||
|
) {
|
||||||
|
if (bufferTimes.current.length < MAX_BUFFER_ENTRIES) {
|
||||||
|
bufferTimes.current.push(bufferTime);
|
||||||
|
} else {
|
||||||
|
bufferTimes.current[bufferIndex.current] = bufferTime;
|
||||||
|
bufferIndex.current = (bufferIndex.current + 1) % MAX_BUFFER_ENTRIES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bufferThreshold = calculateAdaptiveBufferThreshold();
|
||||||
|
|
||||||
|
// if we have > 3 seconds of buffered data and we're still not playing,
|
||||||
|
// something might be wrong - maybe codec issue, no audio, etc
|
||||||
|
// so mark the player as playing so that error handlers will fire
|
||||||
|
if (!isPlaying && playbackEnabled && bufferTime > 3) {
|
||||||
|
setIsPlaying(true);
|
||||||
|
lastJumpTimeRef.current = Date.now();
|
||||||
|
onPlaying?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have more than 10 seconds of buffer, something's wrong so error out
|
||||||
|
if (
|
||||||
|
isPlaying &&
|
||||||
|
playbackEnabled &&
|
||||||
|
(bufferThreshold > 10 || bufferTime > 10)
|
||||||
|
) {
|
||||||
|
onDisconnect();
|
||||||
|
onError?.("stalled");
|
||||||
|
}
|
||||||
|
|
||||||
|
const playbackRate = calculateAdaptivePlaybackRate(
|
||||||
|
bufferTime,
|
||||||
|
bufferThreshold,
|
||||||
|
);
|
||||||
|
|
||||||
|
// if we're above our rolling average threshold or have > 3 seconds of
|
||||||
|
// buffered data and we're playing, we may have drifted from actual live
|
||||||
|
// time
|
||||||
|
if (videoRef.current && isPlaying && playbackEnabled) {
|
||||||
|
if (
|
||||||
|
(isSafari || isIOS) &&
|
||||||
|
bufferTime > 3 &&
|
||||||
|
Date.now() - lastJumpTimeRef.current > BUFFERING_COOLDOWN_TIMEOUT
|
||||||
|
) {
|
||||||
|
// Jump to live on Safari/iOS due to a change of playback rate causing re-buffering
|
||||||
|
jumpToLive();
|
||||||
|
} else {
|
||||||
|
// increase/decrease playback rate to compensate - non Safari/iOS only
|
||||||
|
if (videoRef.current.playbackRate !== playbackRate) {
|
||||||
|
videoRef.current.playbackRate = playbackRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onError != undefined) {
|
||||||
|
if (videoRef.current?.paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferTimeout) {
|
||||||
|
clearTimeout(bufferTimeout);
|
||||||
|
setBufferTimeout(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
setBufferTimeout(
|
||||||
|
setTimeout(() => {
|
||||||
|
if (
|
||||||
|
document.visibilityState === "visible" &&
|
||||||
|
wsRef.current != null &&
|
||||||
|
videoRef.current
|
||||||
|
) {
|
||||||
|
onDisconnect();
|
||||||
|
onError("stalled");
|
||||||
|
}
|
||||||
|
}, 3000),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
bufferTimeout,
|
||||||
|
isPlaying,
|
||||||
|
onDisconnect,
|
||||||
|
onError,
|
||||||
|
onPlaying,
|
||||||
|
playbackEnabled,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!playbackEnabled) {
|
if (!playbackEnabled) {
|
||||||
return;
|
return;
|
||||||
@ -462,91 +556,7 @@ function MSEPlayer({
|
|||||||
}}
|
}}
|
||||||
muted={!audioEnabled}
|
muted={!audioEnabled}
|
||||||
onPause={handlePause}
|
onPause={handlePause}
|
||||||
onProgress={() => {
|
onProgress={onProgress}
|
||||||
const bufferTime = getBufferedTime(videoRef.current);
|
|
||||||
|
|
||||||
if (
|
|
||||||
videoRef.current &&
|
|
||||||
(videoRef.current.playbackRate === 1 || bufferTime < 3)
|
|
||||||
) {
|
|
||||||
if (bufferTimes.current.length < MAX_BUFFER_ENTRIES) {
|
|
||||||
bufferTimes.current.push(bufferTime);
|
|
||||||
} else {
|
|
||||||
bufferTimes.current[bufferIndex.current] = bufferTime;
|
|
||||||
bufferIndex.current =
|
|
||||||
(bufferIndex.current + 1) % MAX_BUFFER_ENTRIES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bufferThreshold = calculateAdaptiveBufferThreshold();
|
|
||||||
|
|
||||||
// if we have > 3 seconds of buffered data and we're still not playing,
|
|
||||||
// something might be wrong - maybe codec issue, no audio, etc
|
|
||||||
// so mark the player as playing so that error handlers will fire
|
|
||||||
if (!isPlaying && playbackEnabled && bufferTime > 3) {
|
|
||||||
setIsPlaying(true);
|
|
||||||
lastJumpTimeRef.current = Date.now();
|
|
||||||
onPlaying?.();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have more than 10 seconds of buffer, something's wrong so error out
|
|
||||||
if (
|
|
||||||
isPlaying &&
|
|
||||||
playbackEnabled &&
|
|
||||||
(bufferThreshold > 10 || bufferTime > 10)
|
|
||||||
) {
|
|
||||||
onDisconnect();
|
|
||||||
onError?.("stalled");
|
|
||||||
}
|
|
||||||
|
|
||||||
const playbackRate = calculateAdaptivePlaybackRate(
|
|
||||||
bufferTime,
|
|
||||||
bufferThreshold,
|
|
||||||
);
|
|
||||||
|
|
||||||
// if we're above our rolling average threshold or have > 3 seconds of
|
|
||||||
// buffered data and we're playing, we may have drifted from actual live
|
|
||||||
// time, so increase playback rate to compensate - non safari/ios only
|
|
||||||
if (
|
|
||||||
videoRef.current &&
|
|
||||||
isPlaying &&
|
|
||||||
playbackEnabled &&
|
|
||||||
Date.now() - lastJumpTimeRef.current > BUFFERING_COOLDOWN_TIMEOUT
|
|
||||||
) {
|
|
||||||
// Jump to live on Safari/iOS due to a change of playback rate causing re-buffering
|
|
||||||
if (isSafari || isIOS) {
|
|
||||||
if (bufferTime > 3) {
|
|
||||||
jumpToLive();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
videoRef.current.playbackRate = playbackRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onError != undefined) {
|
|
||||||
if (videoRef.current?.paused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufferTimeout) {
|
|
||||||
clearTimeout(bufferTimeout);
|
|
||||||
setBufferTimeout(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
setBufferTimeout(
|
|
||||||
setTimeout(() => {
|
|
||||||
if (
|
|
||||||
document.visibilityState === "visible" &&
|
|
||||||
wsRef.current != null &&
|
|
||||||
videoRef.current
|
|
||||||
) {
|
|
||||||
onDisconnect();
|
|
||||||
onError("stalled");
|
|
||||||
}
|
|
||||||
}, 3000),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
if (
|
if (
|
||||||
// @ts-expect-error code does exist
|
// @ts-expect-error code does exist
|
||||||
|
Loading…
Reference in New Issue
Block a user