Add more checks before fallback for hls stream
This commit is contained in:
parent
94dd37a123
commit
75911d01dc
1 changed files with 30 additions and 4 deletions
|
|
@ -196,6 +196,11 @@ const captureFirstFramePoster = async (el: HTMLVideoElement): Promise<void> => {
|
||||||
thumbnail.value = dataUrl
|
thumbnail.value = dataUrl
|
||||||
havePoster.value = true
|
havePoster.value = true
|
||||||
applyMediaSessionMetadata()
|
applyMediaSessionMetadata()
|
||||||
|
|
||||||
|
if (detachDecodeGuard) {
|
||||||
|
detachDecodeGuard()
|
||||||
|
detachDecodeGuard = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|
@ -387,6 +392,7 @@ function attachDecodeFailGuard(el: HTMLVideoElement, onFail: () => void): () =>
|
||||||
let timer: number | null = null
|
let timer: number | null = null
|
||||||
let armed = false
|
let armed = false
|
||||||
let done = false
|
let done = false
|
||||||
|
let playAttempted = false
|
||||||
|
|
||||||
const clearAll = () => {
|
const clearAll = () => {
|
||||||
if (null !== timer) {
|
if (null !== timer) {
|
||||||
|
|
@ -400,6 +406,7 @@ function attachDecodeFailGuard(el: HTMLVideoElement, onFail: () => void): () =>
|
||||||
el.removeEventListener('loadeddata', onLoadedData)
|
el.removeEventListener('loadeddata', onLoadedData)
|
||||||
el.removeEventListener('error', onError)
|
el.removeEventListener('error', onError)
|
||||||
el.removeEventListener('emptied', onError)
|
el.removeEventListener('emptied', onError)
|
||||||
|
el.removeEventListener('play', onPlay)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ok = () => {
|
const ok = () => {
|
||||||
|
|
@ -429,23 +436,30 @@ function attachDecodeFailGuard(el: HTMLVideoElement, onFail: () => void): () =>
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onPlay = () => playAttempted = true
|
||||||
|
|
||||||
const armCheck = () => {
|
const armCheck = () => {
|
||||||
if (armed || done) return
|
if (armed || done) return
|
||||||
armed = true
|
armed = true
|
||||||
|
|
||||||
if ('requestVideoFrameCallback' in el) {
|
if ('requestVideoFrameCallback' in el) {
|
||||||
rvfcId = (el as any).requestVideoFrameCallback(() => ok())
|
rvfcId = (el as any).requestVideoFrameCallback(() => ok())
|
||||||
timer = window.setTimeout(() => fail(), 1000)
|
// Extend timeout for network delays and buffering
|
||||||
|
timer = window.setTimeout(() => fail(), 3000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Give more time for network playback and buffering
|
||||||
timer = window.setTimeout(() => {
|
timer = window.setTimeout(() => {
|
||||||
if (0 === (el as any).videoWidth || 0 === (el as any).videoHeight || 0 === decodedFrames()) {
|
// Only fail if we actually tried to play and have no frames decoded after 3 seconds
|
||||||
|
if (playAttempted && 0 === (el as any).videoWidth && 0 === (el as any).videoHeight && 0 === decodedFrames()) {
|
||||||
fail()
|
fail()
|
||||||
} else {
|
} else if (0 < (el as any).videoWidth || 0 < (el as any).videoHeight || 0 < decodedFrames()) {
|
||||||
|
// Video dimensions or frames are available, stream is working
|
||||||
ok()
|
ok()
|
||||||
}
|
}
|
||||||
}, 800)
|
// If nothing is available yet but video hasn't been played, keep waiting
|
||||||
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onLoadedData = () => armCheck()
|
const onLoadedData = () => armCheck()
|
||||||
|
|
@ -454,6 +468,7 @@ function attachDecodeFailGuard(el: HTMLVideoElement, onFail: () => void): () =>
|
||||||
el.addEventListener('loadeddata', onLoadedData, { once: true })
|
el.addEventListener('loadeddata', onLoadedData, { once: true })
|
||||||
el.addEventListener('error', onError)
|
el.addEventListener('error', onError)
|
||||||
el.addEventListener('emptied', onError)
|
el.addEventListener('emptied', onError)
|
||||||
|
el.addEventListener('play', onPlay)
|
||||||
|
|
||||||
if (4 <= el.readyState || 2 <= el.readyState) {
|
if (4 <= el.readyState || 2 <= el.readyState) {
|
||||||
queueMicrotask(armCheck)
|
queueMicrotask(armCheck)
|
||||||
|
|
@ -466,11 +481,22 @@ const src_error = async () => {
|
||||||
if (hls) {
|
if (hls) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we already successfully captured a frame, that means the streamed video codec is working.
|
||||||
|
if (havePoster.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await nextTick()
|
await nextTick()
|
||||||
if (destroyed.value) {
|
if (destroyed.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if video is actually paused.
|
||||||
|
if (video.value && video.value.paused) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.warn('Source failed to load, attempting HLS fallback...')
|
console.warn('Source failed to load, attempting HLS fallback...')
|
||||||
attach_hls(makeDownload(config, props.item, 'm3u8'))
|
attach_hls(makeDownload(config, props.item, 'm3u8'))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue