From cf698f4456d09d43ac7779377a5736b9711b5113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B0=8F=E4=BA=91?= Date: Wed, 10 Dec 2025 14:24:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=92=AD=E6=94=BE=E5=99=A8?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Wvp.vue | 64 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/src/components/Wvp.vue b/src/components/Wvp.vue index 8122635..bbd6c6d 100644 --- a/src/components/Wvp.vue +++ b/src/components/Wvp.vue @@ -151,9 +151,13 @@ const stopFlv = () => { let hlsPlayer: Hls | null = null const hlsVideoRef = ref(null) const isHlsPlaying = ref(false) +let hlsRetryCount = 0 +const hlsMaxRetries = 5 +let hlsRetryTimer: any = null const playHls = () => { testHlsError.value = '' + hlsRetryCount = 0 if (!hlsVideoRef.value) { testHlsError.value = '视频元素未找到' @@ -165,26 +169,75 @@ const playHls = () => { hlsPlayer = null } + if (hlsRetryTimer) { + clearTimeout(hlsRetryTimer) + hlsRetryTimer = null + } + if (Hls.isSupported()) { try { hlsPlayer = new Hls({ + debug: false, + enableWorker: true, + lowLatencyMode: true, + backBufferLength: 90, xhrSetup: (xhr) => { xhr.withCredentials = true - } + }, + manifestLoadingTimeOut: 10000, + manifestLoadingMaxRetry: 3, + manifestLoadingRetryDelay: 1000, + levelLoadingTimeOut: 10000, + levelLoadingMaxRetry: 4, + fragLoadingTimeOut: 20000, + fragLoadingMaxRetry: 6 }) hlsPlayer.loadSource(hlsUrl.value) hlsPlayer.attachMedia(hlsVideoRef.value) hlsPlayer.on(Hls.Events.MANIFEST_PARSED, () => { + console.log('HLS manifest 解析成功') hlsVideoRef.value?.play() isHlsPlaying.value = true + testHlsError.value = '' }) hlsPlayer.on(Hls.Events.ERROR, (event, data) => { + console.error('HLS 错误:', data) + if (data.fatal) { - testHlsError.value = `播放错误: ${data.type} - ${data.details}` - isHlsPlaying.value = false + switch (data.type) { + case Hls.ErrorTypes.NETWORK_ERROR: + if (data.details === 'manifestLoadError' && hlsRetryCount < hlsMaxRetries) { + // M3U8 文件加载失败,可能是还没生成,等待后重试 + hlsRetryCount++ + testHlsError.value = `M3U8 文件加载失败,正在重试 (${hlsRetryCount}/${hlsMaxRetries})...` + console.log(`HLS 重试 ${hlsRetryCount}/${hlsMaxRetries}`) + + hlsRetryTimer = setTimeout(() => { + if (hlsPlayer) { + hlsPlayer.destroy() + } + playHls() + }, 2000) // 等待 2 秒后重试 + } else { + testHlsError.value = `网络错误: ${data.details}` + isHlsPlaying.value = false + } + break + case Hls.ErrorTypes.MEDIA_ERROR: + testHlsError.value = `媒体错误: ${data.details}` + // 尝试恢复 + if (hlsPlayer) { + hlsPlayer.recoverMediaError() + } + break + default: + testHlsError.value = `播放错误: ${data.type} - ${data.details}` + isHlsPlaying.value = false + break + } } }) } catch (error) { @@ -202,6 +255,10 @@ const playHls = () => { } const stopHls = () => { + if (hlsRetryTimer) { + clearTimeout(hlsRetryTimer) + hlsRetryTimer = null + } if (hlsPlayer) { hlsPlayer.destroy() hlsPlayer = null @@ -210,6 +267,7 @@ const stopHls = () => { hlsVideoRef.value.pause() hlsVideoRef.value.src = '' } + hlsRetryCount = 0 isHlsPlaying.value = false }