Fix video quality for short videos (#5996)

* remove auto level capping

* flush first fragment on loop
This commit is contained in:
Samuel Newman
2024-10-29 15:35:43 +02:00
committed by GitHub
parent 80c5f23da2
commit d1355d52fc
2 changed files with 36 additions and 13 deletions
@@ -33,7 +33,6 @@ export function VideoEmbedInnerWeb({
} }
const hlsRef = useHLS({ const hlsRef = useHLS({
focused,
playlist: embed.playlist, playlist: embed.playlist,
setHasSubtitleTrack, setHasSubtitleTrack,
setError, setError,
@@ -113,14 +112,12 @@ promiseForHls.then(Hls => {
}) })
function useHLS({ function useHLS({
focused,
playlist, playlist,
setHasSubtitleTrack, setHasSubtitleTrack,
setError, setError,
videoRef, videoRef,
setHlsLoading, setHlsLoading,
}: { }: {
focused: boolean
playlist: string playlist: string
setHasSubtitleTrack: (v: boolean) => void setHasSubtitleTrack: (v: boolean) => void
setError: (v: Error | null) => void setError: (v: Error | null) => void
@@ -155,8 +152,8 @@ function useHLS({
if (!hlsRef.current) return if (!hlsRef.current) return
const hls = hlsRef.current const hls = hlsRef.current
if (focused && hls.nextAutoLevel > 0) { // if the current quality level goes above 0, flush the low quality segments
// if the current quality level goes above 0, flush the low quality segments if (hls.nextAutoLevel > 0) {
const flushed: HlsTypes.Fragment[] = [] const flushed: HlsTypes.Fragment[] = []
for (const lowQualFrag of lowQualityFragments) { for (const lowQualFrag of lowQualityFragments) {
@@ -179,6 +176,29 @@ function useHLS({
}, },
) )
const flushOnLoop = useNonReactiveCallback(() => {
if (!Hls) return
if (!hlsRef.current) return
const hls = hlsRef.current
// the above callback will catch most stale frags, but there's a corner case -
// if there's only one segment in the video, it won't get flushed because it avoids
// flushing the currently active segment. Therefore, we have to catch it when we loop
if (
hls.nextAutoLevel > 0 &&
lowQualityFragments.length === 1 &&
lowQualityFragments[0].start === 0
) {
const lowQualFrag = lowQualityFragments[0]
hls.trigger(Hls.Events.BUFFER_FLUSHING, {
startOffset: lowQualFrag.start,
endOffset: lowQualFrag.end,
type: 'video',
})
setLowQualityFragments([])
}
})
useEffect(() => { useEffect(() => {
if (!videoRef.current) return if (!videoRef.current) return
if (!Hls) return if (!Hls) return
@@ -197,16 +217,14 @@ function useHLS({
hls.attachMedia(videoRef.current) hls.attachMedia(videoRef.current)
hls.loadSource(playlist) hls.loadSource(playlist)
// initial value, later on it's managed by Controls
hls.autoLevelCapping = 0
// manually loop, so if we've flushed the first buffer it doesn't get confused // manually loop, so if we've flushed the first buffer it doesn't get confused
const abortController = new AbortController() const abortController = new AbortController()
const {signal} = abortController const {signal} = abortController
const videoNode = videoRef.current const videoNode = videoRef.current
videoNode.addEventListener( videoNode.addEventListener(
'ended', 'ended',
function () { () => {
flushOnLoop()
videoNode.currentTime = 0 videoNode.currentTime = 0
videoNode.play() videoNode.play()
}, },
@@ -248,7 +266,15 @@ function useHLS({
hls.destroy() hls.destroy()
abortController.abort() abortController.abort()
} }
}, [playlist, setError, setHasSubtitleTrack, videoRef, handleFragChange, Hls]) }, [
playlist,
setError,
setHasSubtitleTrack,
videoRef,
handleFragChange,
flushOnLoop,
Hls,
])
return hlsRef return hlsRef
} }
@@ -138,13 +138,10 @@ export function Controls({
useEffect(() => { useEffect(() => {
if (!hlsRef.current) return if (!hlsRef.current) return
if (focused) { if (focused) {
// auto decide quality based on network conditions
hlsRef.current.autoLevelCapping = -1
// allow 30s of buffering // allow 30s of buffering
hlsRef.current.config.maxMaxBufferLength = 30 hlsRef.current.config.maxMaxBufferLength = 30
} else { } else {
// back to what we initially set // back to what we initially set
hlsRef.current.autoLevelCapping = 0
hlsRef.current.config.maxMaxBufferLength = 10 hlsRef.current.config.maxMaxBufferLength = 10
} }
}, [hlsRef, focused]) }, [hlsRef, focused])