Fix video quality for short videos (#5996)
* remove auto level capping
* flush first fragment on loop
(cherry picked from commit d1355d52fc)
This commit is contained in:
@@ -33,7 +33,6 @@ export function VideoEmbedInnerWeb({
|
||||
}
|
||||
|
||||
const hlsRef = useHLS({
|
||||
focused,
|
||||
playlist: embed.playlist,
|
||||
setHasSubtitleTrack,
|
||||
setError,
|
||||
@@ -113,14 +112,12 @@ promiseForHls.then(Hls => {
|
||||
})
|
||||
|
||||
function useHLS({
|
||||
focused,
|
||||
playlist,
|
||||
setHasSubtitleTrack,
|
||||
setError,
|
||||
videoRef,
|
||||
setHlsLoading,
|
||||
}: {
|
||||
focused: boolean
|
||||
playlist: string
|
||||
setHasSubtitleTrack: (v: boolean) => void
|
||||
setError: (v: Error | null) => void
|
||||
@@ -155,8 +152,8 @@ function useHLS({
|
||||
if (!hlsRef.current) return
|
||||
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[] = []
|
||||
|
||||
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(() => {
|
||||
if (!videoRef.current) return
|
||||
if (!Hls) return
|
||||
@@ -197,16 +217,14 @@ function useHLS({
|
||||
hls.attachMedia(videoRef.current)
|
||||
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
|
||||
const abortController = new AbortController()
|
||||
const {signal} = abortController
|
||||
const videoNode = videoRef.current
|
||||
videoNode.addEventListener(
|
||||
'ended',
|
||||
function () {
|
||||
() => {
|
||||
flushOnLoop()
|
||||
videoNode.currentTime = 0
|
||||
videoNode.play()
|
||||
},
|
||||
@@ -248,7 +266,15 @@ function useHLS({
|
||||
hls.destroy()
|
||||
abortController.abort()
|
||||
}
|
||||
}, [playlist, setError, setHasSubtitleTrack, videoRef, handleFragChange, Hls])
|
||||
}, [
|
||||
playlist,
|
||||
setError,
|
||||
setHasSubtitleTrack,
|
||||
videoRef,
|
||||
handleFragChange,
|
||||
flushOnLoop,
|
||||
Hls,
|
||||
])
|
||||
|
||||
return hlsRef
|
||||
}
|
||||
|
||||
@@ -138,13 +138,10 @@ export function Controls({
|
||||
useEffect(() => {
|
||||
if (!hlsRef.current) return
|
||||
if (focused) {
|
||||
// auto decide quality based on network conditions
|
||||
hlsRef.current.autoLevelCapping = -1
|
||||
// allow 30s of buffering
|
||||
hlsRef.current.config.maxMaxBufferLength = 30
|
||||
} else {
|
||||
// back to what we initially set
|
||||
hlsRef.current.autoLevelCapping = 0
|
||||
hlsRef.current.config.maxMaxBufferLength = 10
|
||||
}
|
||||
}, [hlsRef, focused])
|
||||
|
||||
Reference in New Issue
Block a user